字节前端一面整理笔记(三十六)
1. 版本号排序
答案
版本号排序不能直接按字符串比,而要按“点分段”逐位比较。
- 先按
.把版本号拆成数组。 - 每一段转成数字。
- 从左到右逐位比较,哪一位大就说明哪个版本大。
- 如果位数不够,就补
0,比如1.2和1.2.0应视为同级。
2. 事件循环输出题
答案
事件循环的主线是:执行一轮宏任务,然后清空微任务队列,必要时进行渲染,再进入下一轮。
- 常见宏任务:
setTimeout、setInterval、I/O、UI 事件。 - 常见微任务:
Promise.then、queueMicrotask、MutationObserver。 - 所以输出顺序题一般先看同步代码,再看微任务,最后看下一轮宏任务。
3. 限流调度,执行的任务数量不能超过两个
答案
这题本质是“带并发上限的任务调度”。
- 同时只允许 2 个任务处于运行中。
- 任意一个任务完成后,再从等待队列里取下一个补上。
- 结果通常还要按输入顺序回填,而不是按完成顺序返回。
4. 你经常使用 AI 工具吗,对 AI 的熟悉度
答案
AI 相关题最好回答成“工具边界 + 落地方式”。
- AI 适合做样板代码、重构建议、测试用例、文档整理和方案对比。
- 真正落地时要给它足够上下文,比如代码规范、目录结构、接口文档、历史实现和约束规则。
- Skills / MCP / Agent 可以理解为不同层级的能力扩展:Skills 偏可复用能力包,MCP 偏工具和上下文接入协议,Agent 偏任务编排和执行过程。
- AI 不能代替工程判断,核心链路仍然要靠人 review 和兜底。
5. SSE 流式输出 Markdown 时,前端如何处理语法不完整的问题
答案
流式渲染通常是“服务端持续返回分片,前端边收边渲染”。
- 服务端按 chunk 或事件流持续输出内容。
- 前端通过
EventSource、fetch + ReadableStream或封装 SDK 持续读取数据。 - 每拿到一段内容,就追加到消息状态里,再触发局部更新。
- 为了避免频繁重渲染,通常会做分帧刷新、批量合并更新或按 token 缓冲后再刷。
6. 正常工作中的 AI 工作流是什么样
答案
正常工作里的 AI 工作流一般不是“想到什么就问什么”,而是有上下文和约束的。
- 先给 AI 足够上下文,比如目录结构、代码规范、接口文档和目标模块。
- 让它先做方案拆解,再生成代码或测试。
- 关键逻辑必须人工 review,不能直接无脑落地。
- 最后把有效的 prompt、规则和模板沉淀成可复用资产。
7. 如果 AI 生成的代码和项目规范冲突,应该如何约束
答案
约束 AI 代码最有效的方式不是事后抱怨,而是事前给足规则。
- 明确代码规范、目录结构、组件风格、状态管理方式和命名规则。
- 把已有实现或参考文件喂给 AI,让它在现有风格上续写。
- 生成后仍要过 lint、test、review 和关键路径人工检查。
8. 项目很大时,怎么控制上下文和 token 消耗
答案
大项目里不能把整个仓库一股脑塞给模型,通常要分层给上下文。
- 当前任务只提供相关目录、关键文件和接口定义。
- 历史背景做摘要,不直接贴全文。
- 通用知识放到文档或知识库,需要时再检索召回。
- 让模型先定位需要哪些上下文,再按需补充。
9. 使用 new 操作符,整个对象操作会做什么事情
答案
new 的执行过程可以概括成四步。
- 创建一个新对象。
- 把新对象的原型指向构造函数的
prototype。 - 以这个新对象为
this执行构造函数。 - 如果构造函数显式返回对象,就返回它;否则返回新建对象。
10. CommonJS 和 ES6 module 的区别
答案
CommonJS 和 ESM 的核心区别在于加载时机和静态分析能力。
- CommonJS 是运行时加载,典型写法是
require/module.exports。 - ESM 是编译时就能静态分析的模块系统,典型写法是
import/export。 - ESM 更适合 Tree Shaking,浏览器和现代构建工具支持也更好。
11. 0.1 + 0.2 不全等于 0.3 的原因
答案
JavaScript 的 Number 基于 IEEE 754 双精度浮点数。
- 安全整数范围是
-(2^53 - 1)到2^53 - 1。 - 超过这个范围会有精度问题。
- 大数相加不能直接转
Number算,应该按字符串从低位到高位逐位相加并处理进位。 0.1 + 0.2 !== 0.3的根因也是浮点数二进制表示精度误差。
12. 浏览器的安全策略有哪些
答案
浏览器安全策略最核心的是同源策略,它限制不同源脚本随意读取彼此资源。
- 跨域常见解决方案是 CORS、反向代理、JSONP(仅限 GET)。
- 另外还有 CSP、XSS 防护、CSRF 防护、沙箱 iframe 等安全机制。
- 面试里最好补一句:前端只是一层防线,真正的数据权限还是要靠后端控制。
13. 浏览器的渲染机制是怎么样的
答案
浏览器渲染大致分为:解析、构建、布局、绘制、合成。
- 解析 HTML 构建 DOM,解析 CSS 构建 CSSOM。
- DOM 和 CSSOM 合成 Render Tree。
- 然后做 Layout 计算位置和大小。
- 再做 Paint 和 Compositing,把页面显示出来。
14. 怎么避免重排重绘
答案
避免重排重绘的思路是减少高成本样式变更和读写交错。
- 不要频繁修改影响布局的属性,比如
width/height/top/left。 - 批量修改样式,避免一边读布局一边写样式。
- 动画尽量使用
transform和opacity。 - 复杂计算和大批量更新要拆分,避免长任务阻塞主线程。
15. 进程通信方式有哪些,使用场景分别是什么
答案
常见进程通信方式有管道、消息队列、共享内存、Socket 等。
- 管道适合父子进程简单数据传输。
- 消息队列适合异步解耦。
- 共享内存效率高,但同步控制更复杂。
- Socket 适合跨机器、跨进程的网络通信。
16. TCP 是怎么实现可靠传输的
答案
TCP 可靠传输主要靠以下机制保证。
- 序号和确认应答保证数据有序可确认。
- 超时重传保证丢包后还能补发。
- 滑动窗口保证流量控制。
- 拥塞控制保证网络不会被打爆。
17. HTTP3.0 为什么要基于 UDP
答案
HTTP/3 基于 QUIC,而 QUIC 运行在 UDP 之上,主要是为了解决 TCP 的一些历史问题。
- TCP 存在队头阻塞。
- QUIC 可以把连接建立、加密和传输层优化统一起来。
- 在弱网和高延迟场景下,HTTP/3 往往能有更好的体验。
18. React Router 是怎么实现的
答案
React Router 的本质是“监听 URL 变化,然后渲染匹配的组件树”。
- 浏览器端一般基于
history.pushState、replaceState和popstate。 - 路由表负责把路径映射到组件。
- 路由切换时,React 重新渲染对应的页面组件。
19. 微前端的 JS 沙箱和 CSS 沙箱是怎么实现的
答案
微前端沙箱的目标是隔离子应用,避免互相污染。
- JS 沙箱常见做法是代理
window、隔离全局变量、劫持副作用。 - CSS 隔离常见做法是命名空间、样式作用域、Shadow DOM。
- 核心目标是让子应用独立运行、独立卸载,不影响主应用和其他子应用。
20. 正常开发项目时性能优化思路是怎么样的
答案
性能优化建议按“发现问题 -> 定位瓶颈 -> 定向优化 -> 验证结果”来做。
- 先看指标,比如 FCP、LCP、交互延迟、内存和渲染帧率。
- 再定位是网络、JS 执行、DOM 渲染还是资源体积问题。
- 常见手段有拆包、缓存、懒加载、虚拟列表、减少重排重绘。
- 最后用埋点、Lighthouse、Performance 面板验证。
21. 上线虚拟滚动之后怎么监控它是否按预期实现
答案
虚拟滚动上线后,不能只看“能不能滚”,还要看效果和稳定性。
- 监控渲染节点数量是否稳定在预期范围。
- 监控滚动时的帧率、长任务和白屏情况。
- 对异常高度、数据错位、快速滚动闪烁做埋点。
- 结合用户反馈和性能面板做回归验证。