Skip to content

IF · 前端面试题 ​

A 前端域已有 28 篇系统文章,本篇绝大部分题目直接链过去(现已 28 篇全覆盖), 只补充 A 域没有的(HTML 语义化、手写 new/call/apply/bind、TS 工具类型、渲染管线、跨端选型等)。

📌 用法:先看本页的要点判断会不会,不会的点进对应文章系统补。 章序即知识顺序:基础 → 渲染 → 框架 → 架构 → 质量 → 工程化 → 性能 → 平台能力 → 网络 → Node。


高频 Top 10(不会的话优先补这些) ​

#题目去哪补
1防抖与节流的区别,并手写A18
2事件循环:说出这段代码的输出顺序A09
3深拷贝怎么处理循环引用A18
4为什么 z-index: 9999 还是被盖住A06
5React 与 Vue 响应式的本质差异A05
6key 为什么不能用 indexA20
7Fiber 解决了什么问题A20
8XSS / CSRF 的原理与防御A08
9首屏加载慢怎么排查和优化A25 / A10
10Token 该存哪A08

一、HTML 与 CSS ​

Q:为什么要语义化标签?除了可读性还有什么实际收益?(内联)

A:① SEO——爬虫靠语义标签判断内容权重;② 可访问性——屏幕阅读器靠 <nav>/<main> 导航; ③ 默认是可聚焦、可点击的元素(<button> 自带键盘支持,用 div 做按钮要自己补 tabindex/role/键盘事件)。 详见 A14 的可访问性小节。

Q:BFC 是什么,解决什么问题?

A:块级格式化上下文,一块内部布局不影响外部的独立区域。解决三类问题: 外边距合并、浮动导致的父级高度塌陷、自适应两栏。触发:display: flow-root(首选)、overflow 非 visible、浮动、绝对定位。

→ 详见 A06 · CSS 布局体系

Q:水平垂直居中怎么写?

A:现代写法 display: grid; place-items: center,或 flex 的 align-items + justify-content。 老方案:absolute + transform、表格布局。注意 vertical-align 只对行内/table-cell 有效,对块级无效。

→ 详见 A06

Q:z-index: 9999 为什么还是被盖住?

A:z-index 只在同一个层叠上下文内比较。父级若有 transform/opacity<1/z-index 非 auto 等创建了层叠上下文, 子元素再高也被困在父级的层级里。解法:浮层 portal 到 body,或去掉竞争父级的副作用属性。

→ 详见 A06


二、JavaScript 基础 ​

Q:闭包是什么?会导致内存泄漏吗?

A:闭包是"函数 + 其定义时的词法环境"。闭包本身不泄漏——它只是持有引用; 泄漏是因为你没释放对闭包的引用(忘了移除监听、忘了 clear 定时器、把 DOM 存在全局缓存里)。

→ 详见 A09 · JavaScript 运行时

Q:说说事件循环,微任务和宏任务的执行顺序?

A:同步代码 → 清空所有微任务(含新产生的)→ 取一个宏任务 → 回到清空微任务。 Promise.then 是微任务,setTimeout 是宏任务,rAF 属于渲染阶段、在微任务清空后绘制前执行。

→ 详见 A09

Q:手写 new(内联)

js
function myNew(Ctor, ...args) {
  const obj = Object.create(Ctor.prototype)   // ① 以原型建对象
  const res = Ctor.apply(obj, args)           // ② 执行构造,绑定 this
  return (res && typeof res === 'object') ? res : obj  // ③ 构造函数返回对象则用它
}

Q:手写 call / apply / bind(内联)

js
Function.prototype.myCall = function (ctx, ...args) {
  ctx = ctx ?? globalThis
  const key = Symbol('fn')
  ctx[key] = this                 // 把函数挂到上下文上,调用时 this 自然指向 ctx
  const res = ctx[key](...args)
  delete ctx[key]
  return res
}
Function.prototype.myApply = function (ctx, args) {
  return this.myCall(ctx, ...(args ?? []))
}
Function.prototype.myBind = function (ctx, ...pre) {
  const fn = this
  return function F(...rest) {
    // 被 new 调用时,this 指向新实例,此时忽略 bind 的 ctx
    return fn.apply(this instanceof F ? this : ctx, [...pre, ...rest])
  }
}

Q:this 的绑定规则?

A:优先级从高到低:new 绑定 → call/apply/bind 显式绑定 → 对象方法隐式绑定 → 默认绑定 (严格模式下 undefined,非严格下全局对象)。箭头函数没有自己的 this,捕获定义时的外层 this。

Q:var / let / const 的区别?什么是 TDZ?(内联)

A:var 函数作用域、会变量提升且初始化为 undefined、可重复声明; let/const 是块级作用域、存在暂时性死区(TDZ)——声明前访问会直接 ReferenceError(不是 undefined)。 const 约束的是绑定不可变,对象内部属性照样能改(要冻结用 Object.freeze,但只浅层)。

Q:== 的隐式转换规则?(内联,经典陷阱题)

A:记三条就够: ① null == undefined 为 true,且它们不等于任何其他值; ② 数字与字符串比较 → 字符串转数字;布尔值 → 先转数字; ③ 对象与原始值比较 → 对象先 valueOf() 再 toString()。

[] == false      // true   → [] → '' → 0;false → 0
[] == ![]        // true   → ![] 是 false,同上
NaN == NaN       // false  (NaN 不等于任何值,包括自己)

工程结论:一律用 ===,== 只在 x == null 判断"为 null 或 undefined"时可接受。

Q:事件流是怎样的?事件委托有什么用?(内联)

A:三个阶段——捕获(window → 目标)→ 目标 → 冒泡(目标 → window)。 addEventListener 第三个参数 true 表示在捕获阶段触发。 事件委托利用冒泡,把监听挂在父节点上: ① 动态新增的子节点自动生效,不用重新绑定;② 监听器数量从 N 降到 1,省内存。 注意:focus/blur 不冒泡(用 focusin/focusout);需要阻止冒泡用 stopPropagation,别和 preventDefault(阻止默认行为)搞混。

Q:WeakMap / WeakSet 和 Map 有什么区别?为什么能防内存泄漏?(内联)

A:WeakMap 的键必须是对象,且是弱引用——对象被回收时,对应条目自动消失。 所以:不可遍历(没有 size/keys)、不能清空。 用途:给对象挂私有数据、深拷贝时处理循环引用、DOM 节点的元数据缓存(节点移除后自动释放)。 GC 判断可达性时不把弱引用算作引用——这就是"不阻止回收"的原因。

Q:什么是迭代器协议?for...of 和 for...in 的区别?(内联)

A:一个对象有 [Symbol.iterator]() 方法且返回带 next() 的迭代器对象,就是可迭代的—— for...of、展开运算符、解构、Promise.all 都依赖它。 for...of 遍历值(可迭代对象:数组/字符串/Map/Set);for...in 遍历键名(含原型链上的可枚举属性,顺序不保证)→ 数组别用 for...in。

Q:Generator 和 async/await 的关系?(内联)

A:async/await 是 Generator + 自动执行器的语法糖。 Generator 用 function* + yield 暂停与恢复,把异步写成同步的形式; async/await 内置了执行器(自动 next() 并把 Promise 结果传回),还返回 Promise、语义更清晰。 现在几乎不需要手写 Generator 做异步控制,但自定义可迭代对象/惰性序列时它仍然好用。


三、TypeScript ​

Q:interface 和 type 的区别?(内联)

A:interface 可声明合并、可被 extends/implements,适合描述对象结构; type 能做联合/交叉/条件类型/映射类型等类型运算,能力更强但不能合并。 官方建议:描述对象优先 interface,需要类型运算用 type。

Q:手写工具类型(内联)

ts
type MyPartial<T>   = { [K in keyof T]?: T[K] }
type MyRequired<T>  = { [K in keyof T]-?: T[K] }
type MyPick<T, K extends keyof T> = { [P in K]: T[P] }
type MyOmit<T, K extends keyof any> = MyPick<T, Exclude<keyof T, K>>
type MyReturnType<F extends (...a: any) => any> = F extends (...a: any) => infer R ? R : never

Q:infer 用在哪?

A:在 extends 条件类型中推断出一个类型变量,如 ReturnType、Awaited、数组元素类型 T extends (infer U)[] ? U : never。

→ 详见 A03 · TypeScript 进阶


四、浏览器渲染原理 ​

Q:从输入 URL 到页面显示,中间发生了什么?(必考,答到这个深度就够)

① URL 解析 → ② DNS 解析(浏览器/系统/路由器/递归 DNS 逐级缓存)
③ TCP 三次握手 → ④ TLS 握手(HTTPS)→ ⑤ 发 HTTP 请求,拿到响应
⑥ 解析 HTML → 构建 DOM 树(遇到 <script> 无 defer/async 会阻塞)
⑦ 解析 CSS → 构建 CSSOM 树
⑧ DOM + CSSOM → 渲染树(Render Tree,不含 display:none)
⑨ 布局 Layout(算出每个节点的几何位置与尺寸)
⑩ 绘制 Paint(分层、生成绘制指令)
⑪ 合成 Composite(图层合成 → GPU 上屏)

→ 详见 A04 · 浏览器与网络

Q:回流(Reflow)和重绘(Repaint)的区别?怎么减少?(内联)

触发开销
回流 / 重排几何属性变了(尺寸、位置、增删节点、字体、窗口 resize)大(要重算整棵子树布局)
重绘外观变了但几何没变(颜色、背景、visibility)中
合成只改 transform / opacity小(跳过布局与绘制,直接 GPU 合成)

优化:

  • 批量改样式(加 class 而非逐条改 style);
  • 读写分离——避免在循环里"读一次布局属性、写一次样式"造成布局抖动(Layout Thrashing);
  • 动画只用 transform / opacity,或用 will-change 提升为独立合成层(别滥用,每层都吃显存);
  • 复杂计算挪到 Web Worker,长任务拆到 requestIdleCallback / scheduler.postTask。

Q:什么是合成层?为什么 transform 动画更流畅?(内联)

合成层是独立光栅化、可单独移动的图层。改 transform/opacity 时,浏览器跳过布局和绘制, 只在合成线程里换矩阵 → 即使主线程正忙(跑 JS),动画也不会卡。 这就是"用 transform: translateX 代替改 left"的根本原因。

Q:defer 和 async 的区别?(内联)

下载执行时机顺序
普通 script阻塞 HTML 解析下载完立即执行保证
defer并行下载HTML 解析完、DOMContentLoaded 之前执行保证
async并行下载下载完立即执行(会打断解析)不保证

→ 有依赖的用 defer,独立的(埋点/广告)用 async。现代项目用 type="module",默认就是 defer 行为。


五、手写题 ​

本页不重复贴代码——全部实现与边界处理见 A18:

题目要点
防抖 / 节流防抖"最后一次说了算",节流"固定频率";要支持 cancel
深拷贝WeakMap 处理循环引用、Reflect.ownKeys 拷 Symbol、保持原型
Promise.all / retry结果按输入顺序;all 快速失败
并发控制(并发池)始终最多 N 个在跑,结果保持顺序
EventBusSet 存订阅者,on 返回取消函数
compose / 中间件洋葱模型(Koa / Redux)
LRUMap 保插入顺序,重插即移到最新

→ 详见 A18 · 手写题与代码设计


六、框架(React / Vue) ​

Q:React 和 Vue 的响应式本质差异?

A:React 是**"我不知道谁变了"——setState 后从根重新遍历(靠 memo 手动挡); Vue 是"我精确知道谁依赖了这个数据"——依赖收集自动精确更新。 所以 React 把精力花在调度**(Fiber/Lane),Vue 花在精确依赖(Proxy/dep)。

→ 详见 A05

Q:React 为什么要有 Fiber?

A:老架构是递归渲染,不可中断,大组件树会独占主线程几百毫秒(远超 16.67ms 帧预算)导致卡顿。 Fiber 把树改成链表结构 + 工作单元,使 render 阶段可分片、暂停、恢复、重做;commit 阶段仍不可中断。

→ 详见 A20 · 框架底层原理

Q:key 用 index 会怎样?

A:① 性能差——本可复用的节点被判定为"内容变了"; ② 状态错乱——列表头部删除后,index 重排,有状态组件/表单输入会"跟错对象"。 必须用稳定唯一的业务 id。

→ 详见 A20

Q:Vue3 的 ref 和 reactive 怎么选?

A:reactive 用于对象但不能整体替换(会丢响应式);ref 包 .value,可整体替换, 适合基础类型与需要重新赋值的场景。Vue3 用 Proxy 解决了 Vue2 感知不到新增/删除属性和数组下标的问题。

→ 详见 A20

Q:Hooks 的闭包陷阱是什么?(内联)

A:useEffect 里若依赖数组漏写,回调捕获的是当次渲染的旧值(stale closure)。 解法:正确声明依赖;用 useRef 存最新值;或用 useReducer 让更新不依赖闭包里的状态。 另:setState 用函数式更新 setC(c => c + 1) 可避免读到旧值。

Q:状态管理怎么选?服务端数据放哪?

A:服务端状态(接口数据、缓存、loading)交给 TanStack Query,不进 Redux; 客户端 UI 状态用 useState;跨页面共享用 Zustand(Vue 用 Pinia); 需要强审计/时间旅行才用 Redux Toolkit。Signals 是跨框架收敛方向。

→ 详见 A07 · 状态管理演进与选型


七、跨端与渲染模式 ​

Q:Flutter / RN / uni-app / 小程序 怎么选?(跨端必考)

方案渲染方式优势代价
Flutter自绘(Skia/Impeller)跨端一致性最好、性能接近原生、动效强包体积大(+10~20MB)、生态自建、动态化受限
React Native原生控件(JSI/桥)前端心智复用、热更新成熟、体积增量小跨端一致性差、升级易踩坑、复杂动效吃力
uni-app / 小程序WebView / 自绘混合一套码多端(含小程序)、生态成熟性能天花板低、坑多、深度定制难
WebView 套壳WebView成本最低、能复用现有 H5体验最差、被"是不是 App"质疑

判断顺序:先问要不要上应用商店、要不要强动效、团队会什么。 要极致一致 + 能接受体积 → Flutter;要复用 React 团队 + 要热更新 → RN;要覆盖小程序矩阵 → uni-app。

→ 详见 A01 · 跨端方案横向对比

Q:CSR / SSR / SSG / ISR 怎么选?

模式首屏SEO服务端成本适用
CSR慢(白屏 + 水合)差低(纯静态托管)后台系统、重交互应用
SSR快好高(每次请求都渲染)内容站、首屏敏感的商业页
SSG最快好极低文档、博客、营销页
ISR快好低内容量大且会更新(电商详情)

追问:

  • "SSR 的代价是什么?" → 服务端成本、水合(hydration)期间不可交互、TTI 可能不降反升、Node 端内存与异常风险。
  • "什么是水合 mismatch?" → 服务端与客户端渲染结果不一致(时间、随机数、window 判断),React 会警告并回退。解法:把不一致的内容放到 useEffect 后渲染。

→ 详见 A13 · 渲染模式


八、架构与设计模式 ​

Q:微前端解决什么问题?什么时候不该用?

A:解决的是**"多个团队要独立开发、独立发布同一个大型应用"**的组织问题, 顺带解决老系统(AngularJS/jQuery)渐进迁移。 不该用的情况:团队就几个人、技术栈统一、没有独立发布诉求——这时上微前端只是把复杂度从代码搬到基础设施。

方案对比见 IX · 场景题 1.6。 → 详见 A24 · 微前端架构落地

Q:前端项目怎么分层?模块边界怎么定?

A:典型四层——视图层(组件/页面)→ 领域层(业务用例/状态)→ 数据层(API/缓存/适配)→ 基础设施(请求/存储/监控)。 边界原则:依赖只能向内(视图依赖领域,领域不依赖视图);跨层调用走接口/适配器,方便替换与测试。 判断坏味道:utils 里堆业务逻辑、组件里直接写 fetch、一个 hook 300 行。

→ 详见 A17 · 前端架构分层与模块边界

Q:前端常用的设计模式有哪些?(内联)

模式前端典型场景
发布订阅EventBus、状态管理、WebSocket 消息分发
策略模式表单校验规则、支付方式选择、多套主题算法
中间件 / 洋葱模型Koa、Redux、Axios 拦截器
装饰器TS 装饰器、HOC(本质是装饰)、埋点与鉴权包裹
观察者 / 代理Vue 响应式(Proxy)、MobX
单例全局请求实例、监控 SDK、缓存管理器
工厂 / 注册表组件按类型动态渲染(表单引擎的字段工厂)
享元虚拟滚动的节点复用、对象池

面试别背定义,说"我在 XX 场景用它解决了 XX 问题"。

→ 详见 A19 · 前端设计模式


九、质量保障与线上排障 ​

Q:前端测试怎么写?测试金字塔怎么落地?

A:单元测试(多、快)→ 集成测试(中)→ E2E(少、慢、脆)。 优先级:先给纯逻辑(工具函数、状态机、校验、数据转换)写单测,性价比最高; 组件测试用 Testing Library(测行为不测实现,别断言内部 state); E2E 只覆盖主流程(登录 → 下单),用 Playwright/Cypress,跑在 CI 的关键路径上。

追问:

  • "覆盖率要追求 100% 吗?" → 不要。覆盖率是手段不是目标,80% 是常见甜点区,且要看"是不是覆盖了关键分支"。
  • "E2E 很不稳定怎么办?" → 用 data-testid 定位(别用 CSS 选择器)、显式等待而非 sleep、隔离测试数据、重试只用于临时止血。

→ 详见 A11 · 前端测试策略

Q:线上报错怎么定位?(没有源码、用户也不反馈)

A:靠监控闭环: ① SDK 采集 JS 错误 + 资源错误 + 接口异常 + 性能指标(见 IX 1.1); ② 上报带 release 版本号 + Source Map 内部平台反解(不把 map 放公网); ③ 按"错误指纹"聚合、看影响用户数与趋势,定位到具体代码行; ④ 结合用户行为回放 / 面包屑(操作链路)还原现场; ⑤ 修复后看该指纹的错误率是否归零。

→ 详见 A12 · 前端可观测性与线上排障

Q:怎么区分"偶发"和"大面积"问题?(内联)

先看三个分布:按版本(是不是刚发布才有)、按浏览器/机型(兼容性)、按地域/运营商(CDN/网络)。 三个维度都均匀 → 大概率是服务端或并发问题;集中在某个版本 → 回滚;集中在某机型 → 兼容性。


十、工程化与构建 ​

Q:Tree Shaking 为什么没生效?

A:三个必要条件缺一不可:① 必须是 ESM(CJS 的 require 无法静态分析); ② 包要声明 sideEffects: false(否则打包器不敢删可能有副作用的代码); ③ 生产模式。另外别用 export default {} 整体导出。

→ 详见 A21 · 构建工具原理

Q:Vite 为什么比 Webpack 快?

A:开发态用原生 ESM,按需编译、秒级启动;依赖用 esbuild 预构建(Go 编写,快 10~100×); HMR 只重新编译改动的那一个文件。生产构建仍用 Rollup(产物质量优先)。

→ 详见 A21

Q:脚手架的原理?什么时候别自研?

A:核心是 bin 字段 + commander 解析参数 + inquirer 交互 + ejs 渲染模板 + preset 插件机制。 能用 npm create vite + Plop 解决就别自研;自研的正确时机是"项目数多到复制粘贴已失控"。

→ 详见 A26 / A27

Q:前端工程化到底包含哪些东西?(内联,常作为"聊聊你对工程化的理解")

A:一句话——用工具和规范把"写代码之外的所有事"标准化。五块:

块内容
规范ESLint / Prettier / EditorConfig / 提交规范(Commitlint)+ Git Hooks
构建打包器(Vite/Webpack/Rspack)、Babel/SWC、产物分析与优化
质量单测 / E2E / 类型检查 / 覆盖率卡口
交付CI/CD、环境管理、灰度与回滚、产物版本与缓存策略
研发提效脚手架、代码生成(Plop/Hygen)、组件库、Mock、本地代理

Q:代码生成(codegen)适合做什么?什么时候是过度设计?(内联)

适合:高度重复且有固定模板的东西——新建页面/组件骨架、API 类型从 OpenAPI 生成、图标组件、路由配置。 不适合:逻辑差异大、一周改三次的东西——生成出来还得手改,反而多一层维护成本。 判断标准:模板稳定 + 生成次数多(>10 次)才值得做。

→ 详见 A02 · 前端工程化 / A28 · 代码生成与规范化工具链


十一、性能 ​

Q:首屏慢怎么排查?

A:先度量再优化:看 LCP / INP / CLS(真实用户看 P75),再用 Performance 面板找长任务。 归类:TTFB 高→服务端;LCP 高→资源体积/阻塞/渲染模式;INP 高→长任务;CLS 高→尺寸未预留。

→ 详见 A25 · 性能度量与诊断

Q:常见的优化手段有哪些?

A:图片(WebP/尺寸预留/懒加载,首屏图别懒加载)、依赖替换(moment→dayjs)、 路由级 Code Splitting、长列表虚拟滚动、长任务拆分或挪到 Worker、content-visibility、 动画只用 transform/opacity。

→ 详见 A10 · Web 性能优化


十二、Web 平台能力 ​

Q:Web Worker 能干什么、不能干什么?

A:能跑耗时计算(大文件哈希、图像处理、复杂 diff、加解密),不阻塞主线程。 不能碰 DOM、window 大部分 API;通过 postMessage 通信(结构化克隆,大数据用 Transferable 转移所有权避免拷贝)。

→ 详见 A22 · Web 平台能力

Q:有哪些"把活挪出主线程"的手段?(内联,性能优化的进阶答法)

手段适用
Web Worker纯计算、无 DOM 依赖
时间切片 / scheduler.postTask长任务拆成小块,让出主线程
requestIdleCallback低优先级后台任务(埋点上报、预渲染)
OffscreenCanvas在 Worker 里画 Canvas
WASM计算密集且 JS 不够快(编解码、图像、游戏)

Q:PWA 是什么?国内为什么用得少?(内联)

A:三件套——Service Worker(离线缓存与请求代理)+ Manifest(可安装)+ HTTPS。 用得少的原因:iOS 支持受限且安装入口隐蔽、应用商店分发渠道不在手里、国内推送/支付等能力依赖原生。 但 Service Worker 的离线缓存能力依然值得单独用(文档站、弱网场景)。

Q:前端能操作剪贴板 / 文件系统 / 摄像头吗?(内联)

可以,但都有约束:

  • 剪贴板:navigator.clipboard,需 HTTPS + 用户手势授权;
  • 文件系统:File System Access API(Chromium 系为主,兼容性要注意),退化为 <input type="file">;
  • 摄像头/录音:getUserMedia,必须 HTTPS + 显式授权。
  • 通用原则:能力探测(feature detection)+ 优雅降级,别用 UA 判断。

十三、网络与安全 ​

Q:XSS 怎么防?

A:① 输出转义——用 textContent 不用 innerHTML,富文本用 DOMPurify 白名单净化(黑名单必被绕过); ② 禁 eval/new Function/字符串 setTimeout;③ 配 CSP;④ Cookie 加 HttpOnly。 框架默认已转义,危险来自 dangerouslySetInnerHTML / v-html。

→ 详见 A08 · 前端安全

Q:CSRF 怎么防?

A:① SameSite=Lax Cookie(首选);② CSRF Token;③ 校验 Origin/Referer。 用 Authorization: Bearer(Token 不放 Cookie)的方案天然免疫 CSRF。

→ 详见 A08

Q:Token 该存哪?

A:localStorage XSS 一来直接被偷走,不推荐。 推荐:Access Token(短,15min)存内存 + Refresh Token(长)存 HttpOnly + Secure + SameSite Cookie, 过期时用 Refresh 换新 Access。别把 Token 放 URL。

→ 详见 A08

Q:HTTP 缓存策略?发布后用户还是看到旧版本怎么办?

A:HTML 不缓存(no-cache)+ 带 hash 的静态资源永久缓存。内容变了文件名就变, 新版本不会覆盖旧版本,所以不存在"该不该更新"的两难。别给 index.html 设 max-age。

→ 详见 A16 · CI/CD 与部署运维 / A04

Q:history 路由刷新 404 怎么解?

A:服务端必须配 fallback(Nginx try_files $uri /index.html、Cloudflare _redirects)。 另注意发布时先传带 hash 的资源、最后切换 HTML,避免"半新半旧"白屏。

→ 详见 A15 · 路由与数据加载


十四、Node 与全栈 ​

Q:Node 的事件循环和浏览器有什么不同?

A:Node 分 6 个阶段(timers → pending → idle → poll → check → close), process.nextTick 优先于 Promise 微任务,setImmediate 在 check 阶段。 在 I/O 回调里 setImmediate 一定先于 setTimeout(fn, 0)。

→ 详见 A23 · Node.js 与 BFF

Q:BFF 该做什么、不该做什么?

A:该做聚合、裁剪、适配、鉴权转发、缓存; 不该做业务逻辑、直接操作数据库、变成第二个后端。 判断标准:这个逻辑换一个端(App)还成立吗?成立→应该在后端服务。

→ 详见 A23


自检清单 ​

  • [ ] 高频 Top 10 全部能讲清楚,且能手推事件循环输出题
  • [ ] 手写题:防抖节流、深拷贝、Promise 系列、并发池、LRU 能独立写出
  • [ ] 能解释 Fiber / Diff / key / Vue3 Proxy 四条主线
  • [ ] 能说清 XSS / CSRF 原理与防御,以及 Token 存储选型
  • [ ] 能讲清"HTML 不缓存 + hash 资源永久缓存"的发布缓存方案
  • [ ] 能完整说出"输入 URL 到页面显示"的 11 步,并区分回流 / 重绘 / 合成
  • [ ] 能讲清 CSR / SSR / SSG / ISR 的取舍,以及水合(hydration)的代价
  • [ ] 能说清微前端的适用边界(什么时候不该用)与前端分层原则
  • [ ] 能说清 WeakMap 为什么能防泄漏、== 的转换规则、事件流三阶段
  • [ ] 能说出 5 种以上"把活挪出主线程"的手段

相关文档 ​