京东前端 P6 七轮面试整理笔记(二)
1. React 代码实现:页面上实时显示窗口宽度变化
答案
核心思路是:
- 用
useState保存当前窗口宽度。 - 在
useEffect里监听resize事件。 - 初始化时先同步一次
window.innerWidth。 - 组件卸载时移除监听。
- 高频触发时可加节流或防抖。
2. React 为什么不能在 if 里写 useEffect
答案
因为 Hooks 依赖调用顺序。
- React 每次渲染都会按固定顺序读取 Hook。
- 如果某次渲染进入了
if,另一次没进入,Hook 顺序就变了。 - 顺序一乱,React 就无法正确匹配状态和副作用。
一句话:Hooks 必须写在组件顶层,保证每次渲染调用顺序一致。
3. useEffect 的执行机制
答案
- 首次挂载后执行。
- 依赖变化后重新执行。
- 新一轮执行前会先执行上一次的 cleanup。
- 组件卸载时也会执行 cleanup。
useEffect通常是在浏览器绘制后执行,适合请求、订阅、副作用。
4. useRef 和 useState 底层区别
答案
useState用来驱动 UI,更新后会触发重新渲染。useRef用来保存跨渲染周期的可变值,修改ref.current不会触发渲染。useRef常用于 DOM 引用、定时器、缓存对象、上一次值。
一句话:state 驱动视图,ref 保存值但不驱动视图。
5. useEffect 能监听 useRef 值变化吗
答案
默认不能。
ref.current变化不会触发组件重新渲染。useEffect的依赖比较发生在渲染阶段。- 所以仅修改
ref.current不会让 effect 重新执行。
如果真要监听,一般改成:
- 用
useState承担响应式数据。 - 或用额外的版本号 state 触发更新。
6. 为什么 React 不直接支持监听 useRef
答案
因为 useRef 的设计目标就不是响应式状态。
- 它的价值是“值可变,但不引起渲染”。
- 如果
ref也能直接驱动副作用,那和state的边界就模糊了。 - 需要响应式更新时,本来就应该优先用
state。
7. 手写算法:HTML 标签树最大深度
答案
常见做法是扫描标签并维护深度:
- 遇到开始标签,深度加一。
- 遇到结束标签,深度减一。
- 过程中记录最大深度。
- 自闭合标签通常不增加深度。
这题核心考:
- 栈思维。
- 字符串解析。
- 边界处理。
8. SSR、SSG、RSC 原理及优缺点
答案
SSR
- 请求到来时服务端实时生成 HTML。
- 首屏快、SEO 好。
- 缺点是服务器压力更大。
SSG
- 构建阶段提前生成 HTML。
- 页面可直接走 CDN,性能很好。
- 不适合高频动态内容。
RSC
- React Server Components 把部分组件放服务端执行。
- 可以减少客户端 JS 体积。
- 复杂度更高,对架构要求更高。
答题重点:
- HTML 是什么时候生成的。
- 数据在哪一侧获取。
- 客户端 JS 体积怎么变化。
9. Node SSR 为什么会堵塞,怎么解决
答案
常见堵塞原因:
- CPU 密集型计算阻塞事件循环。
- 同步 I/O。
- 渲染树过大。
- 慢接口阻塞。
- 内存泄漏或资源竞争。
常见优化方案:
- 使用流式 SSR。
- 并行请求数据。
- 做缓存和降级。
- 重计算放到 Worker 或子进程。
- 减少同步逻辑。
10. 站点 SEO 怎么做
答案
- 使用语义化 HTML。
- 设置合理的标题、描述、关键词。
- 图片补充
alt。 - 做好 SSR / SSG,提高爬虫可读性。
- 配置 sitemap、robots、canonical。
- 优化移动端体验和页面性能。
11. 平时怎么学习
答案
推荐回答主线:
- 先看官方文档和权威资料。
- 再做最小 demo。
- 再结合真实项目使用。
- 最后做总结沉淀。
一句话:文档 -> 实验 -> 实战 -> 复盘。
12. 遇到比较难的问题怎么解决
答案
- 先明确问题现象。
- 再缩小问题范围。
- 用日志、断点、最小复现验证猜想。
- 找文档、源码、社区资料交叉确认。
- 最后总结成可复用经验。
13. 版本号列表排序
答案
做法:
- 按
.分割版本号。 - 每段转成数字。
- 逐位比较。
- 不足位补
0。
例如 1.2 和 1.2.0,应视为同级。
14. SSR 和分段 SSR / 流式 SSR 架构
答案
- 普通 SSR 是整页数据准备好后一次性返回 HTML。
- 分段 SSR / 流式 SSR 是优先返回首屏可见内容,其余内容分块下发。
- 这样可以更早开始渲染,优化首屏体验。
- 适合复杂页面和慢数据依赖场景。
15. 微前端底层怎么实现,CSS 隔离、通信怎么做
答案
- 主应用负责路由分发、子应用加载和生命周期管理。
- 子应用独立开发、独立部署。
- CSS 隔离常见做法有命名空间、Shadow DOM、样式作用域。
- 通信常见做法有事件总线、共享状态、统一 API、中枢层转发。
16. LLM、MCP 对日常工作的作用
答案
- LLM 可提升检索、写代码、重构、生成测试和文档整理效率。
- MCP 的价值是把模型接入更多工具、文件、命令和上下文。
- 真正落地不是单纯问答,而是把研发流程串起来。
- 但 AI 不能替代 review、架构判断和线上风险控制。
17. 编辑器的多人协作冲突原理
答案
常见方案有:
- OT。
- CRDT。
如果重点讲 OT:
- 把编辑抽象成插入、删除等原子操作。
- 不同用户并发修改时,通过转换函数调整操作位置。
- 目标是让所有副本最终收敛一致。
18. Webpack 的 loader 和 plugin 原理
答案
- Loader 负责模块内容转换,比如把 TS 转 JS、把 CSS 处理成可打包模块。
- Plugin 负责扩展整个构建流程,基于生命周期钩子工作。
一句话:loader 管模块转换,plugin 管构建流程扩展。
19. Webpack 的底层打包原理
答案
- 从 entry 开始分析依赖。
- 构建模块依赖图。
- 用 loader 转换不同资源。
- 在插件钩子中扩展构建流程。
- 最终输出 chunk 和 bundle。
20. ESM、CMD、UMD 区别
答案
- ESM 是官方标准模块系统,支持静态分析和 tree shaking。
- CMD 更偏按需执行,典型代表是 SeaJS。
- UMD 是兼容 CommonJS、AMD 和浏览器全局变量的通用模块格式。
21. React 18 以前批处理和 React 18+ 批处理区别
答案
- React 18 以前,批处理主要发生在 React 自己控制的事件边界里。
- React 18 之后,自动批处理范围更广,异步场景里也能合并更新。
- 本质上是调度层和更新队列的合并能力更强了。
22. useLayoutEffect 和 useEffect 区别
答案
useEffect在浏览器绘制之后执行,不阻塞绘制。useLayoutEffect在 DOM 更新后、浏览器绘制前同步执行,会阻塞绘制。- 所以读布局、同步修正 DOM 时更适合
useLayoutEffect。
23. 微信小程序架构怎么做
答案
- 逻辑层和渲染层分离。
- 两层之间通过桥接通信。
- 页面和组件有自己的更新机制。
- 这样做是为了安全隔离、性能控制和平台统一管理。
24. Wasm 是什么
答案
Wasm 是一种可移植的低级字节码格式。
- 可让 C/C++、Rust 等语言编译后的代码在浏览器中高性能执行。
- 适合音视频、图形、计算密集型场景。
- 它不是为了替代 JS,而是补充 JS 做高性能部分。
25. Rust 所有权
答案
最核心的三点:
- 每个值有且只有一个所有者。
- 所有者离开作用域时值会被释放。
- 借用规则帮助 Rust 在编译期保证内存安全。
26. 用 React 做跨端小程序框架实现
答案
- React 语法层复用组件写法。
- 编译阶段把 JSX 和逻辑转换成目标平台代码。
- 运行时适配不同平台组件、路由和 API。
- 核心难点在于多端能力差异和统一抽象。
27. 怎么做 Node CLI 的插件化
答案
- 核心 CLI 保持稳定,只暴露能力边界。
- 提供插件注册机制、生命周期和 Hook。
- 给插件暴露上下文、命令扩展、配置扩展能力。
- 处理好版本兼容、权限控制和错误隔离。
28. 这套面试高频考点
答案
高频点主要是:
- React Hooks 和底层机制。
- SSR / Node SSR / SEO。
- Webpack 和模块化。
- 微前端、跨端、小程序架构。
- 协作编辑、CLI 插件化、Wasm、Rust。
- 项目难点、学习能力、排障和方案权衡。