腾讯 PCG 前端暑期一面整理笔记(三十三)
2. 项目为什么选择 Vite,辨析 Vite 与 Webpack,Vite 热更新原理是什么
答案
这题其实在同时考 3 件事:
- 你是否理解为什么项目选 Vite
- 你是否理解 Vite 和 Webpack 的差异
- 你是否理解 Vite 的 HMR 原理
推荐回答:
如果是现代前端项目,选择 Vite 的核心原因通常有:
- 启动更快
- 热更新更快
- 配置更轻
- 对 Vue / React / TS 友好
- 新项目开发体验更好
面试表达:
我们选择 Vite,主要是因为它在开发阶段基于原生 ESM 按需加载模块,不需要像传统 bundler 那样先全量打包,所以冷启动和热更新都更快,配置也更轻,更适合现代前端项目。
可以从 5 个维度回答:
1. 开发阶段策略不同
- Webpack 通常是先构建依赖图并打包
- Vite 开发阶段基于浏览器原生 ESM,按需提供模块
2. 启动速度不同
- Webpack 项目越大,启动越容易变慢
- Vite 启动通常更快
3. 热更新方式不同
- Webpack 更偏 bundle 级构建流程
- Vite 更偏模块级更新
4. 配置复杂度不同
- Webpack 更灵活、生态更深
- Vite 更轻、更开箱即用
5. 适用场景不同
- Webpack 更适合历史复杂工程或高度定制项目
- Vite 更适合现代新项目
核心主线:
- 浏览器通过原生 ESM 请求模块
- 开发服务器和客户端建立 WebSocket 连接
- 文件变化后,Vite 只定位受影响模块
- 服务端通过 WebSocket 通知客户端哪个模块更新了
- 客户端重新拉取这个模块
- 如果模块支持 HMR,就只替换对应模块,而不是整页刷新
面试表达:
Vite 的热更新本质是原生 ESM + WebSocket 的模块级 HMR。改动发生后,服务端只通知受影响的模块,客户端重新请求该模块并替换运行,因此热更新更快。
推荐顺序:
- 先讲为什么选 Vite
- 再讲和 Webpack 的本质区别
- 最后讲 HMR 原理
3. Node.js 相较于其他后端的优势是什么
答案
这题不是要你说 Node.js 比 Java、Go、PHP 都强,而是看你是否理解:
- Node.js 的定位
- 它的优势场景
- 它的短板
Node.js 的核心优势主要有:
- 前后端语言统一,协作效率高
- 事件驱动、非阻塞 I/O,适合高并发 I/O 场景
- npm 生态丰富
- JSON 处理天然友好
- 很适合做 BFF、网关、SSR、中台服务、实时通信服务
Node.js 不适合:
- 重 CPU 计算
- 特别复杂的强事务型重后端系统
Node.js 的优势主要在于事件驱动和非阻塞 I/O,特别适合高并发 I/O 密集型场景,比如 BFF、SSR、网关和实时通信服务。另外前后端都能用 JavaScript/TypeScript,团队协作和代码复用效率也更高。它的短板是 CPU 密集型任务不占优。
4. 高并发场景:1s 内对数据库进行 10w 次写入,如何优化
答案
这题不是考“SQL 怎么写更快”,而是考:
高并发写入场景下,系统如何削峰、异步化、批量化。
- 不能让 10w 次请求直接同步打数据库
- 要削峰填谷
- 要异步处理
- 要批量写入
1. 消息队列削峰
请求先写 MQ:
- Kafka
- RabbitMQ
- RocketMQ
后台消费者再异步落库。
2. 批量写入
不要单条 insert,改成:
- batch insert
- 批量提交事务
3. 缓存或内存队列暂存
先写:
- Redis
- 内存队列
再异步刷库。
4. 分库分表
单库单表扛不住时,做水平拆分。
5. 限流和降级
如果写入流量超过系统能力,要:
- 限流
- 排队
- 降级
6. 数据库层优化
- 索引控制
- 连接池优化
- 主从架构
- 写入热点拆分
1 秒 10 万次写入不能直接同步打数据库,核心思路是削峰填谷。常见方案是请求先进入消息队列,后台异步批量写库,同时配合 Redis 暂存、分库分表和连接池优化。如果系统承压过大,还要加限流和降级。也就是说,重点不是单次写得多快,而是把同步直写改成异步批量写。
5. Git:本地 commit 5 次,未 push,回滚到第 3 次,如何找回第 4、5 次提交
答案
考察:
- 你是否知道 Git 里 HEAD 移动历史可以找回
- 你是否知道
reflog
第一步:查看引用历史
git reflog
第二步:找到第 4、5 次提交的 commit hash
第三步:恢复方式
如果想直接恢复到第 5 次提交:
git reset --hard <commit-hash>
如果只想把第 4、5 次提交重新摘回来:
git cherry-pick <hash4>
git cherry-pick <hash5>
虽然本地已经回滚到了第 3 次,但只要第 4、5 次提交曾经存在过,一般都可以通过 git reflog 找回。reflog 会记录 HEAD 的移动历史,找到对应提交 hash 后,可以 reset 回去,或者 cherry-pick 把它们摘回来。
6. 辨析 XSS 与 CSRF 攻击
答案
XSS 的本质是:
攻击者把恶意脚本注入页面,并在用户浏览器中执行。
常见危害:
- 窃取 Cookie / Token
- 篡改页面
- 冒充用户操作
常见类型:
- 存储型 XSS
- 反射型 XSS
- DOM 型 XSS
CSRF 的本质是:
攻击者诱导用户在已登录状态下,对目标站点发起非本人意愿的请求。
它成立的关键前提:
- 用户已经登录目标站点
- 浏览器会自动携带身份信息,比如 Cookie
XSS
重点是:
- 恶意脚本注入
- 在页面中执行
CSRF
重点是:
- 冒用用户身份
- 伪造请求
XSS 防御
- 输入校验
- 输出转义
- 避免
innerHTML直插 - CSP
- Cookie 设置
HttpOnly
CSRF 防御
- CSRF Token
- SameSite Cookie
- 校验 Referer / Origin
- 关键操作二次确认
XSS 是把恶意脚本注入页面并执行,核心风险是脚本执行;CSRF 是利用用户已登录状态伪造请求,核心风险是请求伪造。XSS 重点防注入和脚本执行,CSRF 重点防请求伪造。
7. 自动化脚本向输入框中填入 1000w 个手机号,发起获取验证码功能,前端如何防范或规避
答案
一定要先说:
前端只能提高攻击成本,不能作为核心安全防线,真正的防御一定在后端。
-
按钮防抖和节流
-
倒计时限制重复发送
-
图形验证码 / 滑块验证码
-
风险行为识别
-
禁止高频切换手机号
-
异常操作埋点上报
-
IP 限流
-
设备指纹
-
用户维度限频
-
验证码校验
-
风控模型
-
黑名单机制
前端可以通过按钮节流、倒计时、图形验证码、滑块验证、异常行为识别等方式提高脚本攻击成本,但前端无法真正防住伪造请求。核心还是要依赖后端限流、设备指纹、验证码校验和风控策略。面试里要明确说“前端只能辅助,后端才是主防线”。
8. 算法题:硬币找零问题
答案
给定硬币数组 coins 和金额 amount,求凑出该金额所需的最少硬币数;如果无法凑出,返回 -1。
这是经典动态规划题。
状态定义
dp[i] 表示凑出金额 i 所需的最少硬币数。
转移方程
如果当前使用一枚 coin:
dp[i] = min(dp[i], dp[i - coin] + 1)
初始化
dp[0] = 0- 其余初始化为
Infinity
返回值
如果 dp[amount] 仍然是无穷大,返回 -1
function coinChange(coins, amount) {
const dp = new Array(amount + 1).fill(Infinity)
dp[0] = 0
for (const coin of coins) {
for (let i = coin; i <= amount; i++) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1)
}
}
return dp[amount] === Infinity ? -1 : dp[amount]
}
- 时间复杂度:
O(coins.length * amount) - 空间复杂度:
O(amount)
可以主动补一句:
这题本质是完全背包问题,因为每种硬币都可以重复使用。