字节抖音前端暑期二面整理笔记(三十五)
1. 你说的打包技术指的是 Webpack 还是 Vite
答案
如果项目里既提过 Webpack 又提过 Vite,建议先说明主用哪一个,再对比原因。
- Webpack 生态更老更全,适合历史项目和高度定制场景。
- Vite 开发态基于原生 ESM,冷启动和热更新通常更快,适合现代前端项目。
- 如果面试官追问,一定补上:开发态和生产构建的策略不一样,不能只说“Vite 更快”。
2. 你是前后端都开发吗,包括 Node.js 吗
答案
可以回答成“我有前后端协作能力,Node.js 主要用于中间层和工程化场景”。
- Node.js 适合做 BFF、网关、SSR、脚手架和 I/O 密集型服务。
- 如果自己项目里做过接口转发、上传服务、流式返回,就可以直接举例。
- 面试里不要把 Node.js 说成“万能后端”,要强调它更擅长的场景。
3. 讲一下浏览器里的宏任务和微任务
答案
事件循环的主线是:执行一轮宏任务,然后清空微任务队列,必要时进行渲染,再进入下一轮。
- 常见宏任务:
setTimeout、setInterval、I/O、UI 事件。 - 常见微任务:
Promise.then、queueMicrotask、MutationObserver。 - 所以输出顺序题一般先看同步代码,再看微任务,最后看下一轮宏任务。
4. 浏览器事件循环和 Node.js 事件循环有什么区别
答案
事件循环的主线是:执行一轮宏任务,然后清空微任务队列,必要时进行渲染,再进入下一轮。
- 常见宏任务:
setTimeout、setInterval、I/O、UI 事件。 - 常见微任务:
Promise.then、queueMicrotask、MutationObserver。 - 所以输出顺序题一般先看同步代码,再看微任务,最后看下一轮宏任务。
5. 看代码说答案:事件循环相关
答案
事件循环的主线是:执行一轮宏任务,然后清空微任务队列,必要时进行渲染,再进入下一轮。
- 常见宏任务:
setTimeout、setInterval、I/O、UI 事件。 - 常见微任务:
Promise.then、queueMicrotask、MutationObserver。 - 所以输出顺序题一般先看同步代码,再看微任务,最后看下一轮宏任务。
6. 强缓存和协商缓存有什么区别
答案
强缓存和协商缓存的区别在于:是否需要再向服务器确认。
- 强缓存靠
Cache-Control或Expires,命中时浏览器直接用本地缓存,不发请求。 - 协商缓存会发请求,由服务端根据
ETag/Last-Modified判断是否返回304。 - 实战里常见做法是静态资源走强缓存 + 文件指纹,HTML 走协商缓存。
7. TypeScript 里 type 和 interface 有什么区别
答案
使用 TypeScript 的核心价值是提升可维护性和协作效率。
- 它能在开发阶段提前发现类型错误。
- 对接口模型、复杂表单、组件库和状态管理非常有帮助。
- 重构时更安全,IDE 提示也更完整。
- 团队项目里,类型本身也是一种文档。
8. 项目中 type 和 interface 怎么选择
答案
interface 更适合描述对象结构,支持声明合并;type 更灵活,适合联合类型、交叉类型和别名。
- 描述接口对象、组件 props、返回值模型时,很多团队更偏向用
interface。 - 做复杂类型运算、联合字面量、映射类型时,更适合用
type。 - 本质不是谁绝对更好,而是看团队规范和场景。
9. 介绍一下 SSE 的实现
答案
SSE 的实现核心是服务端持续推送事件流,客户端持续监听。
- 服务端返回
text/event-stream。 - 客户端通过
EventSource或流式读取持续接收数据。 - 每条消息按事件格式解析,再更新页面状态。
10. SSE 和 WebSocket 有什么区别
答案
SSE 和 WebSocket 的核心区别是通信方向和适用场景。
- SSE 是服务端单向推送,基于 HTTP,天然适合大模型文本流、通知流、日志流。
- WebSocket 是全双工通信,更适合聊天、协同编辑、实时互动。
- AI 对话里如果主要是服务端不断吐内容,SSE 往往更简单、更稳定,也更容易复用现有 HTTP 鉴权和网关体系。
- 如果需要客户端高频主动发消息、双向实时同步,WebSocket 更合适。
11. 为什么你的 AI 对话项目选择 SSE 而不是 WebSocket
答案
SSE 和 WebSocket 的核心区别是通信方向和适用场景。
- SSE 是服务端单向推送,基于 HTTP,天然适合大模型文本流、通知流、日志流。
- WebSocket 是全双工通信,更适合聊天、协同编辑、实时互动。
- AI 对话里如果主要是服务端不断吐内容,SSE 往往更简单、更稳定,也更容易复用现有 HTTP 鉴权和网关体系。
- 如果需要客户端高频主动发消息、双向实时同步,WebSocket 更合适。
12. 你的多轮对话项目只支持文字,还是也支持图片修改
答案
这类题核心是把你的 AI 产品链路说清楚。
- 如果当前只支持文字,就直接说明当前能力边界,不要虚构支持图片。
- 再补充未来如果扩展图片、文件、多模态,需要新增的协议字段、渲染组件和状态管理。
- 项目里 AI 的主链路通常是:用户输入 -> 上下文组装 -> 模型请求 -> 流式返回 -> 前端增量渲染 -> 会话持久化。
13. 如果要支持图片加工创作,和纯文字对话设计上有什么不同
答案
多模态流式内容一般不能只当纯字符串处理,推荐把服务端返回统一抽象成消息片段流。
- 每个片段带上
type,例如text、image、pdf、markdown、component。 - 前端先按协议解析,再分发给不同渲染器组件。
- 文本流可以增量更新;图片、文件类内容更适合先展示占位状态,拿到完整地址后再渲染。
- 多轮图片编辑相比纯文字对话,额外要管理素材引用、版本关系、操作指令和结果回显。
14. 多轮图片编辑或多轮文字对话出现意图偏移,怎么优化
答案
多模态流式内容一般不能只当纯字符串处理,推荐把服务端返回统一抽象成消息片段流。
- 每个片段带上
type,例如text、image、pdf、markdown、component。 - 前端先按协议解析,再分发给不同渲染器组件。
- 文本流可以增量更新;图片、文件类内容更适合先展示占位状态,拿到完整地址后再渲染。
- 多轮图片编辑相比纯文字对话,额外要管理素材引用、版本关系、操作指令和结果回显。
15. 上下文过长导致语义偏移,工程上怎么优化
答案
上下文过长时,不能把所有历史消息无脑拼给模型,通常要做分层管理。
- 近期强相关消息保留原文。
- 远期历史做摘要压缩,只保留结论、约束和关键事实。
- 对知识性内容走 RAG 检索,不直接全量塞进上下文。
- 如果出现意图偏移,可以把系统约束、用户目标和关键上下文单独固定在高优先级区域。
16. 你的上下文摘要压缩策略是怎么做的
答案
上下文过长时,不能把所有历史消息无脑拼给模型,通常要做分层管理。
- 近期强相关消息保留原文。
- 远期历史做摘要压缩,只保留结论、约束和关键事实。
- 对知识性内容走 RAG 检索,不直接全量塞进上下文。
- 如果出现意图偏移,可以把系统约束、用户目标和关键上下文单独固定在高优先级区域。
17. 讲一下你虚拟列表的整体实现思路
答案
虚拟列表实现思路一般是:
- 根据滚动位置计算当前可视区范围。
- 只渲染这一小段数据。
- 通过占位容器撑开整体滚动高度。
- 滚动时动态更新起止索引。
18. Markdown 安全渲染里怎么防止 XSS
答案
Markdown 安全渲染的核心是“不要把不可信内容直接当 HTML 执行”。
- 先把 Markdown 解析成结构化 AST。
- 对 HTML 标签、属性做白名单过滤,危险协议如
javascript:必须拦截。 - 对富文本渲染通常会配合
DOMPurify一类库做二次清洗。 - 如果支持代码块、链接、图片,也要分别校验 URL、事件属性和内联脚本。
19. 为什么选择做后台管理系统这个项目
答案
项目题建议按“背景、目标、职责、难点、结果”来回答。
- 先说项目是做什么的,面向谁,解决什么问题。
- 再说页面结构和核心模块,比如会话区、输入区、历史记录、设置区、文件区等。
- 说明自己负责的部分,不要泛泛说“都做了”。
- 最后讲 1 到 2 个真正的难点,比如流式渲染、状态管理、性能优化、上传链路、权限模型,并补充最终效果。
20. 大文件分片上传是怎么实现的
答案
文件上传这类题建议按完整链路回答:
- 前端先按大小阈值切片,通常 2MB 到 10MB 比较常见。
- 上传前计算文件 hash,服务端据此判断是否已存在完整文件或部分分片。
- 断点续传时,前端先查询已上传分片列表,只补传缺失分片。
- 全部分片上传完成后,通知服务端按顺序合并。
- 秒传一般基于完整文件 hash;分片 hash 更多用于断点续传和重复分片复用。
- 分片不是越多越好:分太小请求数会暴涨,分太大失败重传成本高,所以要结合网络、文件大小和后端承载能力权衡。
21. JWT 双 Token 登录机制是怎么设计的
答案
双 Token 方案一般是 access token + refresh token。
access token生命周期短,用于日常接口访问。refresh token生命周期长,用于换取新的access token。- 单点登录通常依赖统一身份中心,多个系统共享登录态,前端只是消费统一登录结果。
- 生产里要考虑并发刷新、失效重登和登出联动。
22. 怎么基于双 Token 实现单点登录
答案
双 Token 方案一般是 access token + refresh token。
access token生命周期短,用于日常接口访问。refresh token生命周期长,用于换取新的access token。- 单点登录通常依赖统一身份中心,多个系统共享登录态,前端只是消费统一登录结果。
- 生产里要考虑并发刷新、失效重登和登出联动。
23. 权限管理是怎么设计的
答案
权限管理一般分四层:
- 路由级:控制页面能不能进。
- 菜单级:控制导航是否可见。
- 按钮级:控制具体操作是否可点。
- 数据级:控制能看到哪些数据。
前端主要负责展示和交互限制,真正的权限校验一定要以后端为准。
24. AI 生成代码和你手写代码的比例大概是多少
答案
这题不建议报一个夸张比例,重点是说明边界。
- 重复性、样板化代码会更多借助 AI。
- 核心业务逻辑、架构设计和线上修复仍然以自己主导为主。
- 更好的表达是:AI 提升了效率,但最终质量和正确性仍由我负责。
25. 看代码说答案:this 指向相关
答案
判断 this 指向时,按优先级看:
new绑定。call/apply/bind显式绑定。- 隐式绑定,也就是谁调用函数,
this指向谁。 - 默认绑定,浏览器非严格模式下一般是
window,严格模式下是undefined。 - 箭头函数不适用这套规则,它只看定义时的外层作用域。
26. 严格模式下 this 的输出有什么变化
答案
严格模式下,this 的默认绑定会更严格。
- 普通函数直接调用时,非严格模式下
this通常指向window;严格模式下是undefined。 - 作为对象方法调用时,
this仍然指向调用它的对象。 - 箭头函数没有自己的
this,始终继承外层词法作用域。
27. 实现带最大并发数限制的 Promise.all
答案
带并发限制的 Promise.all 核心是维护一个“运行中任务池”。
- 同时只启动
k个任务。 - 任意一个任务完成后,再从等待队列里补一个新的进去。
- 结果数组要按输入顺序回填,而不是按完成顺序 push。
- 全部任务结束后再统一 resolve;如果设计成首错即停,要在出错时及时 reject。
28. LC101 对称二叉树
答案
这题本质是判断左右子树是否互为镜像。
- 递归比较左子树的左节点和右子树的右节点。
- 再比较左子树的右节点和右子树的左节点。
- 如果两个节点都为空,返回 true;一个空一个不空或值不同,返回 false。