真实场景 · 排查流程 · DevTools技巧 · 思维模型 · 手把手排查
白屏是前端最常见也最让人慌的问题。按照下面的流程走,99% 的白屏都能在 10 分钟内定位原因。
白屏就像手机App开门了但客人看到空荡荡的柜台 —— 是吧台没搭好(JS没加载)?是配方丢了(路由配错)?还是供货商没来(接口挂了)?挨个检查!
| # | 原因 | 现象 | 排查 / 解决 |
|---|---|---|---|
| 1 | JS 报错(入口 crash) | Console 红色报错,页面空白 | 看 Console 红色报错,定位到具体文件和行号。常见:变量未定义、import 路径错误 |
| 2 | 路由配置错误 | 刷新 404,首页能进子页面不行 | history 模式需要 nginx 配置 try_files;或改用 hash 模式 |
| 3 | CSP / 白名单限制 | Console 提示 Refused to load | 检查 meta 标签 CSP 策略和响应头 Content-Security-Policy |
| 4 | 打包路径错误 | Network 里 JS/CSS 404 | 检查 vite 的 base 或 webpack 的 publicPath 配置 |
| 5 | 接口报错导致渲染失败 | 组件 render 报错,整棵树崩了 | 加 ErrorBoundary(React)/ onErrorCaptured(Vue);接口调用加 try-catch |
| 6 | CSS 加载失败 | 页面内容在但完全无样式 | 检查 Network 面板 CSS 文件是否 404;检查 extract 插件配置 |
DevTools 就是手机App的后厨监控屏 —— 哪台机器卡了(长任务)、哪个原料没了(请求失败)、哪杯手机App做错了(数据不对),一目了然!
| 断点类型 | 用法 | 适用场景 |
|---|---|---|
| 普通断点 | 点行号左侧设置 | 代码走到这里时暂停,逐行调试 |
| 条件断点 | 右键行号 → "Add conditional breakpoint" | 只在满足条件时断,如 userId === 123 |
| XHR 断点 | Sources → XHR/fetch Breakpoints → 填 URL | 某个接口请求时自动断住 |
| DOM 断点 | Elements 面板右键元素 → Break on | DOM 被修改时断住,排查谁改了节点 |
| 事件监听断点 | Sources → Event Listener Breakpoints | click/scroll 等事件触发时断住 |
快捷键:F8 继续执行 | F10 单步跳过 | F11 单步进入 | Shift+F11 跳出
• 红色请求 = 失败(看状态码:404 找不到、500 服务器错、CORS 被 block)
• 瀑布流 = 看加载顺序,哪个请求卡住了后面的(瓶颈在哪)
• Filter = 输入关键词快速过滤(如输入 "api" 只看接口)
• 右键 → Copy as cURL = 把请求复制成命令行,直接给后端同事复现
• Disable cache = 勾上后每次都是全新请求,排除缓存干扰
• 强制状态:点击 :hov 按钮,勾选 :hover / :focus / :active,不用鼠标悬停也能看样式
• 修改样式:直接在 Styles 面板改数值,实时看效果(调试布局神器)
• Box Model:看 margin / border / padding / content 的实际尺寸
• Computed:看最终生效的样式值(优先级最高的那个)
• 红色三角 = 长任务(>50ms),需要优化
• Main 线程 = 看 JS 执行耗时
• Summary 饼图 = Loading / Scripting / Rendering / Painting 各占多少
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 开发代理 | vite/webpack devServer 代理到后端 | 零配置后端,开发环境最常用 | 只适合开发环境 |
| nginx 反向代理 | 同域转发,浏览器不知道后端在哪 | 生产环境标准方案 | 需要运维配 nginx |
| 后端 CORS 头 | 服务端返回 Allow-Origin 响应头 | 灵活,支持多域名 | 需要后端改代码 |
| JSONP | 利用 script 标签不受同源限制 | 兼容老浏览器 | 只支持 GET,有安全风险,已过时 |
• 前端超时:检查 axios/fetch 的 timeout 配置,默认可能只有 10s
• 后端慢:Network 面板看 Waiting (TTFB) 耗时,如果这个很长说明后端处理慢
• 网络慢:Content Download 耗时长,可能是返回数据太大或网络差
• DNS 解析慢:看 Timing 面板 Stalled 阶段,首次请求慢可能是 DNS 解析
• 请求参数不对 → 检查前端序列化(JSON.stringify? FormData?)
• 响应数据不对 → 把请求 Copy as cURL 给后端同事
• 都对但页面显示不对 → 检查前端数据处理逻辑
CSS 排版就像手机App摆桌椅 —— 椅子不见了(display:none)、桌子挤到门外了(overflow)、装修图纸和实际不一样(盒模型)。用 Elements 面板一看就知道!
• display: none → 完全消失,不占空间。检查是谁设置的(JS?媒体查询?)
• visibility: hidden → 不可见但占空间。检查是否有动画/过渡残留
• opacity: 0 → 透明但占空间且可点击。常见于动画未结束
• overflow: hidden → 内容被裁切了。检查父容器的 overflow 和高度
• z-index 太低 → 被其他元素盖住了。在 Elements 面板看层级
• height: 0 → 高度为 0。检查子元素是否 float 没清(BFC 问题)
• width/height 超出父容器 → 检查是否设了固定宽度,改成 max-width
• overflow 值不对 → 需要滚动加 overflow: auto,需要隐藏加 overflow: hidden
• box-sizing → 检查是不是 content-box 导致 padding 撑大了。全局加 box-sizing: border-box
• 长单词/URL → 加 word-break: break-all 或 overflow-wrap: break-word
• margin 塌陷 → 父子元素的上外边距合并了。解决方案:给父元素加 overflow: hidden 或 padding-top: 1px
• BFC → 触发 BFC 隔离布局:overflow: hidden / display: flow-root / position: absolute
• position 用错了 → relative 是相对自身偏移,absolute 是相对最近的定位祖先,fixed 是相对视口
• flex 布局 → 检查 justify-content / align-items / flex-shrink / flex-grow 是否符合预期
1px 边框问题
移动端 1px 边框在高 DPI 屏幕上看起来很粗。用 transform 缩放:
安全区适配(刘海屏 / 底部横条)
内存泄漏 = 用完的东西没扔掉,越积越多,最后页面卡死甚至崩溃。
SPA(单页应用)特别容易泄漏,因为:
• 页面不会整页刷新(没有天然的重置)
• 组件反复挂载/卸载,每次都可能留下残留
• 路由切换时,旧页面的事件监听器、定时器可能没清理
内存泄漏就像手机App的垃圾桶忘了倒 —— 用的杯子、吸管一直往里扔,但从来没清过,最后垃圾桶满了,店都转不开了。SPA 不刷新页面 = 垃圾桶永远不倒!
判断标准:操作前后,如果 Detached DOM 节点在增长,或者某个对象数量只增不减,大概率就是泄漏了。
| # | 泄漏场景 | 原因 | 修复 |
|---|---|---|---|
| 1 | 定时器未清除 | setInterval/setTimeout 组件卸载后还在跑 | 在 beforeUnmount/useEffect cleanup 中 clearInterval |
| 2 | 事件监听未移除 | addEventListener 后没有 removeEventListener | 卸载时移除;或用 AbortController |
| 3 | 闭包引用 | 闭包持有外部变量,导致无法 GC | 及时置空引用,避免不必要的闭包 |
| 4 | DOM 引用 | JS 变量引用了已移除的 DOM 节点 | DOM 移除后把 JS 引用置为 null |
| 5 | 全局变量/缓存 | 往 window 上挂数据,页面不刷新就不会释放 | 避免全局变量;使用弱引用 WeakMap/WeakSet |
构建报错就像手机App开业前检查不合格 —— 组件过期了(依赖版本冲突)、配方写错了(语法错误)、厨房太大塞不进(包太大)。不要慌,看报错信息!
• Module not found → 路径写错了或没安装这个包。检查 import 路径和 node_modules
• SyntaxError → 语法错误。看报错的文件和行号,可能是少了括号/分号
• ENOENT: no such file → 文件路径不存在。检查大小写(Mac 不敏感但 Linux 敏感!)
• Heap out of memory → Node 内存不够。加 NODE_OPTIONS=--max-old-space-size=4096
• digit envelope routines::unsupported → Node 17+ 和 OpenSSL 不兼容。加 NODE_OPTIONS=--openssl-legacy-provider
Lighthouse 会给出 5 个维度的评分:
• Performance(性能)→ 加载速度
• Accessibility(无障碍)→ 辅助功能
• Best Practices(最佳实践)→ 安全和规范
• SEO(搜索引擎优化)→ 可搜索性
• PWA(渐进式 Web 应用)→ 离线可用性
LCP(Largest Contentful Paint)= 客人等到第一杯手机App的时间。1/2/4 内装杯=好/需改进/差。优化:压缩图片、预加载关键资源、CDN 加速。
FID / INP(First Input Delay / Interaction to Next Paint)= 打开App后多久开始做手机App。50/100/200ms=好/需改进/差。优化:减少 JS 阻塞主线程、代码分割、延迟加载非关键脚本。
CLS(Cumulative Layout Shift)= App界面不要乱跳!客人正要打开App,App界面突然位移了。0.05/0.1/0.25=好/需改进/差。优化:图片/视频设固定宽高比、避免动态插入内容、字体预加载。
| 指标 | 含义 | 好 | 需改进 | 差 | 优化方向 |
|---|---|---|---|---|---|
| LCP | 最大内容绘制时间 | ≤2.5s | ≤4s | >4s | 压缩图片、预加载、CDN |
| INP | 交互响应延迟 | ≤200ms | ≤500ms | >500ms | 减少主线程阻塞、代码分割 |
| CLS | 累积布局偏移 | ≤0.1 | ≤0.25 | >0.25 | 固定宽高、预留空间 |
打开 DevTools Console,看有没有红色报错
打开 DevTools Network,看 JS/CSS 文件是否全部加载成功(状态码 200)
看 HTML 里有没有 <div id="app"></div>(挂载点存在吗)
如果是 SPA 路由问题,刷新后白屏 → 检查 history 模式和 nginx 配置
检查 CSP 策略:Console 有没有 Refused to load 报错
检查 publicPath / base 配置:资源路径是否正确
如果是接口报错导致 → 加 ErrorBoundary / try-catch 兜底
看 Network 面板:请求发出去了吗?状态码多少?
4xx 错误 → 检查请求参数、URL、Header 是否正确
5xx 错误 → 后端问题,把 cURL 转给后端同事
CORS 报错 → 检查是否配置了代理或 CORS 头
请求超时 → 看是前端 timeout 配置太短还是后端真的慢
数据不对 → 对比 Request Payload 和 Response,定位是前端还是后端的问题
Cookie / Token 没带上 → 检查 withCredentials 或 Authorization Header
跑一次 Lighthouse,看具体得分和建议
LCP 慢 → 检查最大元素(通常是图片)是否压缩、是否用 CDN
INP 慢 → Performance 面板看长任务,减少主线程阻塞
CLS 高 → 检查图片/广告位是否有固定尺寸
首屏慢 → 检查是否做了代码分割(路由懒加载)
内存持续增长 → Memory 面板拍快照对比,排查泄漏
包体积大 → 用 rollup-plugin-visualizer 分析,按需引入依赖
最重要的一条经验:遇到前端问题先打开 DevTools!90% 的问题 Console + Network + Elements 三个面板就能定位。不要上来就改代码猜答案,先看报错信息说什么。