前端调试随笔
遇到 bug,先缩小范围,再选工具。
先问四件事:出在 PC、移动端;移动端是 iOS、Android,系统浏览器、微信,还是自家 App WebView;稳定必现还是偶现(偶现记下机型、网络、操作路径);换账号、清本地数据、换环境是否还在——只有某批用户有,优先查缓存、Cookie、接口数据和灰度。
范围缩到移动端页面后,先嵌 vConsole、Eruda,看报错、请求和 Storage。页面内工具不够(要看 DOM、CSS、断点、性能)再上真机:iOS 用 Safari,Android 用 chrome://inspect、Edge。
调试指南
异步问题
异步行为:动画、HTTP 请求、DOM 渲染(布局、绘制)、定时器(setTimeout、setInterval)、Promise、async、requestAnimationFrame。
排查:回调有没有按预期顺序执行、有没有在数据回来之前就用了结果、多个请求是否互相覆盖(竞态)。控制台里对 Promise 开「异步堆栈」,或在关键点打断点,比只看同步调用栈清楚。
缓存问题
缓存可以出现在浏览器(强缓存、协商缓存)、CDN、中间代理、路由器,以及 localStorage、sessionStorage、Service Worker Cache。
- 实例一:CDN 里缓存的 jQuery 文件不完整,部分用户打开页面出错。节点不一致时,本地复现不了,前端很难定位。
- 实例二:
localStorage在某些情况下已经不能再用(配额、隐私模式、数据格式升级),却没有有效的清除或版本号机制,旧数据一直把逻辑带偏。
注意:硬刷新只能清当前浏览器;CDN 要按 URL 或缓存键刷新。Service Worker 还要单独注销或更新,否则会继续拦截请求。
网络问题
第三方脚本挂了、部分地区链路差、页面协议和资源协议不一致(HTTP、HTTPS),都会表现为有些用户正常使用,有些用户页面报错或空白。
- 实例一:微信好友分享失败。页面用了协议相对地址
//cdn.example.com/x.js。在微信里打开时,基协议不一定是https:,资源解析错或被拦截。现行做法是资源写死https://,页面本身也走 HTTPS。
HTTPS 页里再引 HTTP 脚本会被浏览器当混合内容拦截。接口跨域失败时,先分清是 DNS、证书、CORS、状态码,不要都当成是网络问题。
语法与 API 兼容
页面在 A 浏览器正常、B 浏览器白屏或报错,先分清是语法过不了,还是运行时 API 没有,还是 CSS、权限策略不同。
语法:let、箭头函数、类、可选链、空值合并等,目标引擎解析不了,脚本在执行前就挂。靠构建期转译(Babel、SWC、TypeScript)。
运行时 API:同不同浏览器、不同 WebView 内核实现对 API 的支持情况不一。
- 垫片能补:
Promise、Array.prototype.findIndex、Object.assign。 - 单独垫或换实现的 DOM、Web API:
IntersectionObserver、ResizeObserver、AbortController、crypto.randomUUID、navigator.clipboard。 - 垫片补不了:CSS 新增的一些属性(旧 Safari 的 flex gap、100dvh、backdrop-filter),以及权限类 API(剪贴板、摄像头在 HTTP、iframe、微信 WebView 里被禁或行为不同)。
不同浏览器内核不一样:桌面 Chrome、Edge、Safari、Firefox;移动端还有 iOS WKWebView、Android System WebView、各厂商系统浏览器,以及微信等 App 自带内核。
典型场景:
- 实例一:数组
findIndex方法未进行转义,部分低端机执行失败,控制台几乎没有可用堆栈,定位困难。
Cookie 问题
请求带不上 Cookie,常见原因:
- 用户或浏览器关了 Cookie。
- 跨站发送被拦:
SameSite=Lax、Strict默认不带跨站 Cookie;要跨站带 Cookie 需SameSite=None; Secure(Chrome 等还在收紧第三方 Cookie)。 - CORS 要带 Cookie 时,服务端必须
Access-Control-Allow-Credentials: true,且Access-Control-Allow-Origin为具体源,不能是*。 - 前端用 JS 写 Cookie 时,同名、同 path 会互相覆盖。
实际场景:
- 实例一:开了 Mock.js 拦截 Ajax 后,导出请求带不上 Cookie,浏览器报跨域。Mock.js 会替换 XHR,和真实的凭证、CORS 行为不一致,联调带 Cookie 的接口时应关掉拦截。
- 实例二:本地页在 iOS 上循环登录。Cookie 跨站带不过去。App 内 WebView 要在系统设置里允许跨网站跟踪(Safari、App → 允许跨网站跟踪);服务端 Cookie 也要对齐
SameSite、Secure、域名。 - 实例三:页面反复提示未登录。前端按 URL 参数用 JS 重写了
token(或同域名两个项目都写token,登录态互相覆盖)。
调试工具
- Chrome DevTools:Chrome 内置,查 DOM、CSS、网络、断点、性能的主力。
- Firefox DevTools:Firefox 内置。旧的 Firebug 已停更,不要再装。
- vConsole:腾讯出的手机网页调试面板,可打日志、看请求。
- Eruda:移动端迷你控制台,能看日志、元素、XHR、Storage、Cookie。
- 微信开发者工具:公众号网页调试 + 小程序调试。
- Fiddler:抓 HTTP、HTTPS,可断点、改请求和响应。现在分 Classic、Everywhere。
- Charles:HTTP 代理、监视、反向代理,看本机与外网的请求、响应和头(含 Cookie、缓存)。
- Mock.js:生成随机数据并拦截 Ajax。
移动端真机调试
iOS 真机调试
用 Mac 上的 Safari 远程调试 iPhone、iPad 里的页面:
- Mac Safari 打开开发菜单:Safari → 设置 → 高级 → 在菜单栏中显示「开发」菜单(旧版在「偏好设置」里)。
- iOS:设置 → Safari → 高级 → 打开 Web 检查器。
- App WebView:安装包须是可调试包。iOS 16.4 起 WKWebView 还要把
isInspectable打开。设备 UDID 要在证书、描述文件里(设置加入白名单)。 - 数据线连上后,Mac Safari 菜单「开发」里选中设备,再选页面。
页面里临时看日志,也可以嵌入 vConsole、Eruda,不依赖线连。
Android 真机调试
用电脑上的 Chrome、Edge 远程调试手机里的 Chrome 标签页,以及开启了调试的 App WebView。
- 打开开发者模式:设置 → 关于手机 → 连续点版本号(各品牌路径略有差别)。
- 开发者选项里打开 USB 调试;USB 连接模式选「传输文件、MTP」,不要停在仅充电。必要时允许「未知来源」才能装调试包。
- 数据线连上后,电脑 Chrome 打开
chrome://inspect/#devices,勾选 Discover USB devices,设备出现后再 inspect。 - App 内 WebView 还要在原生代码里打开
WebView.setWebContentsDebuggingEnabled(true),并安装可调试包。生产包默认关,inspect 里看不到。
电脑要能识别设备:安装 Android platform-tools,终端里 adb devices 能看到设备且状态是 device。Mac 上拷文件可用 Android File Transfer,须在插线前先打开该软件;远程调试靠的是 adb,不是 File Transfer。
Chrome 无法打开安卓 App 上的页面?
现在很多安卓机在 chrome://inspect 里看不到设备,或能看到但一点 inspect 就是白屏、HTTP/1.1 404 Not Found。常见原因:
- DevTools 前端拉不下来。 点 inspect 后,Chrome 要去
chrome-devtools-frontend.appspot.com拉对应版本的调试页,国内网络经常失败。以前还有 inspect fallback,现在很多版本已经没有这项。 - 电脑和手机内核版本对不上。 远程调试走 Chrome DevTools Protocol,电脑浏览器版本低于手机 Chrome、Android System WebView 时,协议对不上,设备列表空,或 inspect 打不开。
- 页面不在可调试的内核里。 厂商系统浏览器、微信、支付宝等 App 内 WebView,很多不向
chrome://inspect暴露调试端口。用户用的是这些壳,不是官方 Chrome。华为等无 GMS 的机器,Chrome、WebView 更新通道也不同,远程调试更不稳定。
总结
遇到 bug 先定范围:PC、移动端、iOS、Android、稳定还是偶现、是否跟用户和数据有关;移动端先 vConsole,再真机。难复现的问题多半落在异步时序、多层缓存、协议与地区网络、语法、API 内核兼容不统一、Cookie 的跨站与互相覆盖。桌面用 DevTools 和抓包。