文章目录

字节前端一面整理笔记(三十六)

1. 版本号排序

答案

版本号排序不能直接按字符串比,而要按“点分段”逐位比较。

  1. 先按 . 把版本号拆成数组。
  2. 每一段转成数字。
  3. 从左到右逐位比较,哪一位大就说明哪个版本大。
  4. 如果位数不够,就补 0,比如 1.21.2.0 应视为同级。

2. 事件循环输出题

答案

事件循环的主线是:执行一轮宏任务,然后清空微任务队列,必要时进行渲染,再进入下一轮。

  1. 常见宏任务:setTimeoutsetInterval、I/O、UI 事件。
  2. 常见微任务:Promise.thenqueueMicrotaskMutationObserver
  3. 所以输出顺序题一般先看同步代码,再看微任务,最后看下一轮宏任务。

3. 限流调度,执行的任务数量不能超过两个

答案

这题本质是“带并发上限的任务调度”。

  1. 同时只允许 2 个任务处于运行中。
  2. 任意一个任务完成后,再从等待队列里取下一个补上。
  3. 结果通常还要按输入顺序回填,而不是按完成顺序返回。

4. 你经常使用 AI 工具吗,对 AI 的熟悉度

答案

AI 相关题最好回答成“工具边界 + 落地方式”。

  1. AI 适合做样板代码、重构建议、测试用例、文档整理和方案对比。
  2. 真正落地时要给它足够上下文,比如代码规范、目录结构、接口文档、历史实现和约束规则。
  3. Skills / MCP / Agent 可以理解为不同层级的能力扩展:Skills 偏可复用能力包,MCP 偏工具和上下文接入协议,Agent 偏任务编排和执行过程。
  4. AI 不能代替工程判断,核心链路仍然要靠人 review 和兜底。

5. SSE 流式输出 Markdown 时,前端如何处理语法不完整的问题

答案

流式渲染通常是“服务端持续返回分片,前端边收边渲染”。

  1. 服务端按 chunk 或事件流持续输出内容。
  2. 前端通过 EventSourcefetch + ReadableStream 或封装 SDK 持续读取数据。
  3. 每拿到一段内容,就追加到消息状态里,再触发局部更新。
  4. 为了避免频繁重渲染,通常会做分帧刷新、批量合并更新或按 token 缓冲后再刷。

6. 正常工作中的 AI 工作流是什么样

答案

正常工作里的 AI 工作流一般不是“想到什么就问什么”,而是有上下文和约束的。

  1. 先给 AI 足够上下文,比如目录结构、代码规范、接口文档和目标模块。
  2. 让它先做方案拆解,再生成代码或测试。
  3. 关键逻辑必须人工 review,不能直接无脑落地。
  4. 最后把有效的 prompt、规则和模板沉淀成可复用资产。

7. 如果 AI 生成的代码和项目规范冲突,应该如何约束

答案

约束 AI 代码最有效的方式不是事后抱怨,而是事前给足规则。

  1. 明确代码规范、目录结构、组件风格、状态管理方式和命名规则。
  2. 把已有实现或参考文件喂给 AI,让它在现有风格上续写。
  3. 生成后仍要过 lint、test、review 和关键路径人工检查。

8. 项目很大时,怎么控制上下文和 token 消耗

答案

大项目里不能把整个仓库一股脑塞给模型,通常要分层给上下文。

  1. 当前任务只提供相关目录、关键文件和接口定义。
  2. 历史背景做摘要,不直接贴全文。
  3. 通用知识放到文档或知识库,需要时再检索召回。
  4. 让模型先定位需要哪些上下文,再按需补充。

9. 使用 new 操作符,整个对象操作会做什么事情

答案

new 的执行过程可以概括成四步。

  1. 创建一个新对象。
  2. 把新对象的原型指向构造函数的 prototype
  3. 以这个新对象为 this 执行构造函数。
  4. 如果构造函数显式返回对象,就返回它;否则返回新建对象。

10. CommonJS 和 ES6 module 的区别

答案

CommonJS 和 ESM 的核心区别在于加载时机和静态分析能力。

  1. CommonJS 是运行时加载,典型写法是 require/module.exports
  2. ESM 是编译时就能静态分析的模块系统,典型写法是 import/export
  3. ESM 更适合 Tree Shaking,浏览器和现代构建工具支持也更好。

11. 0.1 + 0.2 不全等于 0.3 的原因

答案

JavaScript 的 Number 基于 IEEE 754 双精度浮点数。

  1. 安全整数范围是 -(2^53 - 1)2^53 - 1
  2. 超过这个范围会有精度问题。
  3. 大数相加不能直接转 Number 算,应该按字符串从低位到高位逐位相加并处理进位。
  4. 0.1 + 0.2 !== 0.3 的根因也是浮点数二进制表示精度误差。

12. 浏览器的安全策略有哪些

答案

浏览器安全策略最核心的是同源策略,它限制不同源脚本随意读取彼此资源。

  1. 跨域常见解决方案是 CORS、反向代理、JSONP(仅限 GET)。
  2. 另外还有 CSP、XSS 防护、CSRF 防护、沙箱 iframe 等安全机制。
  3. 面试里最好补一句:前端只是一层防线,真正的数据权限还是要靠后端控制。

13. 浏览器的渲染机制是怎么样的

答案

浏览器渲染大致分为:解析、构建、布局、绘制、合成。

  1. 解析 HTML 构建 DOM,解析 CSS 构建 CSSOM。
  2. DOM 和 CSSOM 合成 Render Tree。
  3. 然后做 Layout 计算位置和大小。
  4. 再做 Paint 和 Compositing,把页面显示出来。

14. 怎么避免重排重绘

答案

避免重排重绘的思路是减少高成本样式变更和读写交错。

  1. 不要频繁修改影响布局的属性,比如 width/height/top/left
  2. 批量修改样式,避免一边读布局一边写样式。
  3. 动画尽量使用 transformopacity
  4. 复杂计算和大批量更新要拆分,避免长任务阻塞主线程。

15. 进程通信方式有哪些,使用场景分别是什么

答案

常见进程通信方式有管道、消息队列、共享内存、Socket 等。

  1. 管道适合父子进程简单数据传输。
  2. 消息队列适合异步解耦。
  3. 共享内存效率高,但同步控制更复杂。
  4. Socket 适合跨机器、跨进程的网络通信。

16. TCP 是怎么实现可靠传输的

答案

TCP 可靠传输主要靠以下机制保证。

  1. 序号和确认应答保证数据有序可确认。
  2. 超时重传保证丢包后还能补发。
  3. 滑动窗口保证流量控制。
  4. 拥塞控制保证网络不会被打爆。

17. HTTP3.0 为什么要基于 UDP

答案

HTTP/3 基于 QUIC,而 QUIC 运行在 UDP 之上,主要是为了解决 TCP 的一些历史问题。

  1. TCP 存在队头阻塞。
  2. QUIC 可以把连接建立、加密和传输层优化统一起来。
  3. 在弱网和高延迟场景下,HTTP/3 往往能有更好的体验。

18. React Router 是怎么实现的

答案

React Router 的本质是“监听 URL 变化,然后渲染匹配的组件树”。

  1. 浏览器端一般基于 history.pushStatereplaceStatepopstate
  2. 路由表负责把路径映射到组件。
  3. 路由切换时,React 重新渲染对应的页面组件。

19. 微前端的 JS 沙箱和 CSS 沙箱是怎么实现的

答案

微前端沙箱的目标是隔离子应用,避免互相污染。

  1. JS 沙箱常见做法是代理 window、隔离全局变量、劫持副作用。
  2. CSS 隔离常见做法是命名空间、样式作用域、Shadow DOM。
  3. 核心目标是让子应用独立运行、独立卸载,不影响主应用和其他子应用。

20. 正常开发项目时性能优化思路是怎么样的

答案

性能优化建议按“发现问题 -> 定位瓶颈 -> 定向优化 -> 验证结果”来做。

  1. 先看指标,比如 FCP、LCP、交互延迟、内存和渲染帧率。
  2. 再定位是网络、JS 执行、DOM 渲染还是资源体积问题。
  3. 常见手段有拆包、缓存、懒加载、虚拟列表、减少重排重绘。
  4. 最后用埋点、Lighthouse、Performance 面板验证。

21. 上线虚拟滚动之后怎么监控它是否按预期实现

答案

虚拟滚动上线后,不能只看“能不能滚”,还要看效果和稳定性。

  1. 监控渲染节点数量是否稳定在预期范围。
  2. 监控滚动时的帧率、长任务和白屏情况。
  3. 对异常高度、数据错位、快速滚动闪烁做埋点。
  4. 结合用户反馈和性能面板做回归验证。