> For the complete documentation index, see [llms.txt](https://lizh.gitbook.io/knowledge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lizh.gitbook.io/knowledge/bugs/00-qian-duan-tiao-shi-sui-bi.md).

# 前端调试随笔

遇到 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](https://developer.chrome.com/docs/devtools/)：Chrome 内置，查 DOM、CSS、网络、断点、性能的主力。
* [Firefox DevTools](https://firefox-source-docs.mozilla.org/devtools-user/)：Firefox 内置。旧的 Firebug 已停更，不要再装。
* [vConsole](https://github.com/Tencent/vConsole)：腾讯出的手机网页调试面板，可打日志、看请求。
* [Eruda](https://www.npmjs.com/package/eruda)：移动端迷你控制台，能看日志、元素、XHR、Storage、Cookie。
* [微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/devtools.html)：公众号网页调试 + 小程序调试。
* [Fiddler](https://www.telerik.com/fiddler)：抓 HTTP、HTTPS，可断点、改请求和响应。现在分 Classic、Everywhere。
* [Charles](https://www.charlesproxy.com/)：HTTP 代理、监视、反向代理，看本机与外网的请求、响应和头（含 Cookie、缓存）。
* [Mock.js](http://mockjs.com/)：生成随机数据并拦截 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](https://developer.android.com/tools/releases/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 和抓包。
