前端调试技巧
Chrome DevTools 是前端最核心的调试工具。本文覆盖各面板的核心用法、实战技巧和常见调试场景。
打开方式:F12 或 Ctrl + Shift + I(Mac: Cmd + Option + I)
Console 面板
输出方法
js
console.log('普通输出') // 最常用的日志输出,显示在 Console 面板
console.warn('警告信息') // 黄色背景 + 警告图标,提示潜在问题
console.error('错误信息') // 红色背景 + 错误图标 + 堆栈跟踪
console.info('信息提示') // 蓝色图标,用于信息性提示
// 表格形式(数组/对象更直观)
console.table([ // 将数组或对象以表格形式展示
{ name: '张三', age: 25, role: '前端' }, // 表格每行对应一个对象
{ name: '李四', age: 30, role: '后端' } // 点击列头可排序
])
// 分组(嵌套内容折叠显示)
console.group('请求流程') // 创建一个可折叠的日志组
console.log('1. 发起请求') // 组内的日志会缩进显示
console.log('2. 等待响应')
console.log('3. 解析数据')
console.groupEnd() // 结束日志组
// 分组(默认折叠)
console.groupCollapsed('详细信息') // 创建默认折叠的日志组
console.log('...')
console.groupEnd()
// 计时(测量某段代码执行时间)
console.time('接口请求') // 开始计时,参数是计时器名称
await fetch('/api/user') // 要测量的异步操作
console.timeEnd('接口请求') // 结束计时并输出耗时,如:接口请求: 156.78ms
// 计数(统计函数被调用了几次)
function handleClick() {
console.count('点击次数') // 每次调用自动递增计数,如:点击次数: 1, 2, 3...
}
// 断言(条件为 false 时才输出)
console.assert(user !== null, 'user 不能为空') // 当第一个参数为 false 时,输出红色错误信息
// 查看调用堆栈
console.trace('调试位置') // 打印从哪里调用到这里的完整调用链(堆栈)格式化输出
js
// %c 自定义样式(区分日志来源)
console.log('%c 成功', 'color: #52c41a; font-weight: bold; font-size: 14px')
console.log('%c 警告', 'color: #faad14; background: #fffbe6; padding: 2px 8px')
console.log('%c 错误', 'color: #ff4d4f; background: #fff2f0; padding: 2px 8px')
// 组合样式
console.log(
'%c API %c GET /api/user %c 200 %c 156ms',
'background: #1890ff; color: white; padding: 2px 6px',
'color: #1890ff',
'background: #52c41a; color: white; padding: 2px 6px',
'color: #999'
)
// 占位符
console.log('用户: %s, 年龄: %d', '张三', 25) // %s 字符串, %d 数字
console.log('数据: %o', { name: '张三' }) // %o 展开对象
console.log('DOM: %O', document.getElementById('app')) // %O 详细 DOM 信息Console 快捷变量
js
// $0 — 当前在 Elements 面板选中的元素
$0 // 等于 document.querySelector('当前选中的元素')
$0.style.color = 'red' // 直接修改选中元素的样式
$0.__vue__ // Vue 2 组件实例(仅 Vue 2)
$0.__vueParentComponent // Vue 3 组件实例(Vue 3 使用)
// $1 — 上一次选中的元素($2, $3, $4 同理)
// $_ — 上一次执行结果
2 + 2 // 执行
$_ // 4(上一次结果)
// $(selector) — document.querySelector 的简写
$('div.container') // 等于 document.querySelector('div.container')
// $$(selector) — document.querySelectorAll 的简写
$$('.item') // 等于 [...document.querySelectorAll('.item')]
// copy() — 复制到剪贴板
copy({ name: '张三', age: 25 }) // 对象复制到剪贴板,可直接粘贴
copy($$('.item').map(el => el.textContent))
// monitor() — 监控函数调用(自动打印参数和返回值)
function add(a, b) { return a + b }
monitor(add)
add(1, 2) // 输出: function add called with arguments: 1, 2
// 输出: function add returned: 3
unmonitor(add) // 取消监控
// debug() / undebug() — 在函数内部自动断点
debug(myFunction) // 下次调用 myFunction 时自动暂停(进入调试器)
undebug(myFunction) // 取消断点Elements 面板
快捷操作
| 快捷键 | 说明 |
|---|---|
Ctrl + Shift + C | 元素选择模式(鼠标点哪选哪) |
H | 切换元素隐藏/显示(选中元素后按) |
F2 | 编辑元素属性 |
| 双击元素/属性 | 直接编辑 |
Delete | 删除选中元素 |
Ctrl + Z | 撤销操作 |
Ctrl + D | 选中下一个同名元素(多光标编辑) |
强制元素状态
选中元素后,Styles 面板点击 :hov 按钮:
:hover— 鼠标悬停状态:active— 激活状态(鼠标按下):focus— 聚焦状态:focus-within— 子元素聚焦:visited— 已访问链接:focus-visible— 键盘聚焦
样式调试技巧
Styles 面板操作:
1. 点击属性名/值可直接编辑
2. 点击空白处可添加新属性
3. 取消勾选属性前的复选框可临时禁用
4. 点击属性旁的三个点 → 可添加 !important、class 伪类
Computed 面板:
- 查看最终计算后的样式(解决优先级冲突)
- 点击某个属性可跳转到定义它的源文件
- 展开箭头可查看继承的样式Box Model 可视化
Computed 面板底部的盒模型图:
- 点击数值可直接修改
- 从外到内:margin → border → padding → content
- 不同颜色区分各区域查找事件监听器
js
// Console 中查找元素绑定的事件
getEventListeners(document.getElementById('btn'))
// 输出: { click: [{ listener: f, useCapture: false, type: "click" }] }
// Elements 面板 → Event Listeners 标签页
// - 查看元素绑定的所有事件
// - 展开可看到事件处理函数的源码位置
// - 点击可跳转到 Sources 面板中的函数定义DOM 断点
Elements 面板 → 右键元素 → Break on:
- subtree modifications — 子节点增删改
- attribute modifications — 属性变化
- node removal — 节点被删除
触发后代码会在对应位置暂停,调用栈中可看到是哪段 JS 修改了 DOM。Network 面板
过滤请求
| 过滤方式 | 说明 | 示例 |
|---|---|---|
| 类型过滤 | 点击标签页 | Fetch/XHR、JS、CSS、Img、WS |
| 文本过滤 | 输入关键字 | api/user |
| 状态码过滤 | status: | status:404、status:5 |
| 方法过滤 | method: | method:POST |
| 大小过滤 | larger-than: | larger-than:100k |
| 域名过滤 | domain: | domain:api.example.com |
| 排除 | - 前缀 | -status:200(排除成功的) |
请求详情
点击某个请求查看:
Headers 标签页:
- General — URL、方法、状态码
- Response Headers — 服务端返回的头(Content-Type、Cache-Control 等)
- Request Headers — 浏览器发送的头(Cookie、Authorization 等)
- Query String Parameters — GET 参数
- Request Payload — POST 请求体
Preview 标签页:
- JSON 响应自动格式化(可展开/折叠)
- 图片直接预览
Response 标签页:
- 原始响应内容
Timing 标签页:
- Queued — 排队等待
- Stalled — 停滞(浏览器并发限制)
- DNS Lookup — DNS 解析
- Initial connection — TCP 连接
- SSL — SSL 握手
- TTFB — 等待服务端响应(首字节时间)
- Content Download — 下载内容
实用操作
1. 右键请求 → Copy → Copy as cURL
复制为 cURL 命令,可在终端直接执行(复现请求)
2. 右键请求 → Copy → Copy response
复制响应内容
3. 右键请求 → Block request URL
屏蔽该请求(模拟接口失败)
4. 右键请求 → Replay XHR
重新发送该请求
5. 导出 HAR 文件
右键请求列表 → Save all as HAR with content
可发给同事分析网络问题模拟网络状态
Network 面板 → Throttle 下拉菜单:
- Online — 正常网络
- Fast 4G — 快速 4G
- Slow 3G — 慢速 3G(测试弱网体验)
- Offline — 断网(测试离线功能)
Local Overrides(本地覆盖响应)
1. Sources → Overrides → 选择本地文件夹
2. Network 面板 → 右键请求 → Save for overrides
3. 修改保存的文件内容
4. 刷新页面,请求会返回你修改的内容
用途:不改后端代码,本地 mock 接口响应Sources 面板(JS 调试)
断点类型
大白话解释: 断点就像"暂停键"。代码执行到断点处会暂停,让你看看当时的情况(变量是什么值、执行了哪些代码)。
各种断点的用途:
- 行断点:最常用,点一下行号就行
- 条件断点:只在特定情况下暂停(比如
i === 100,只在第 100 次循环时暂停) - 日志断点:不暂停,只打印日志(比 console.log 好,不用改代码)
- DOM 断点:当 DOM 元素被修改时暂停(排查"元素被谁改了")
- XHR 断点:当请求发出时暂停(排查"请求参数对不对")
- 异常断点:当代码报错时暂停(排查"哪里报错了")
| 断点 | 设置方式 | 用途 |
|---|---|---|
| 行断点 | 点击行号 | 最常用,代码执行到该行暂停 |
| 条件断点 | 右键行号 → Add conditional breakpoint | 只在条件为 true 时暂停 |
| 日志断点 | 右键行号 → Add logpoint | 不暂停,只打印日志(替代 console.log) |
| DOM 断点 | Elements 面板右键 → Break on | DOM 变化时暂停 |
| XHR 断点 | 右侧面板 → XHR/fetch Breakpoints | 请求发出时暂停(输入 URL 关键字) |
| 事件断点 | 右侧面板 → Event Listener Breakpoints | 特定事件触发时暂停 |
| 异常断点 | 右侧面板 → Pause on exceptions | 抛出异常时暂停 |
| 函数断点 | Console 中 debug(fn) | 调用指定函数时暂停 |
条件断点示例
js
// 只在 id 为 123 时暂停
item.id === 123
// 只在第 5 次循环时暂停
i === 5
// 只在特定用户时暂停
user.name === '张三'
// 只在错误状态时暂停
response.code !== 0日志断点(替代 console.log)
右键行号 → Add logpoint → 输入表达式:
`用户: ${user.name}, 状态: ${status}`
效果:不暂停,不改代码,在 Console 中打印日志。
比 console.log 更好:不用改源码,不用重新构建。调试操作
| 快捷键 | 说明 |
|---|---|
F8 / Ctrl + \ | 继续执行(到下一个断点) |
F10 | 单步跳过(执行当前行,不进入函数) |
F11 | 单步进入(进入函数内部) |
Shift + F11 | 单步跳出(从当前函数返回) |
Ctrl + Shift + F8 | 条件断点管理器 |
Ctrl + F8 | 切换当前行断点开关 |
调试面板区域
右侧调试面板:
Call Stack(调用栈)
- 显示从入口到当前断点的完整调用链
- 点击某一行可跳转到该位置
- 右键 → Restart frame 可重新执行该函数
Scope(作用域)
- Local — 当前函数的局部变量
- Closure — 闭包引用的变量
- Global — 全局变量
- 点击值可直接修改(调试时临时改变量值)
Watch(监听表达式)
- 点击 + 添加表达式
- 实时显示表达式的值
- 常用:this.$data(Vue 数据)、store.state(Vuex)
Breakpoints(断点列表)
- 管理所有断点
- 可批量启用/禁用/删除Snippets(代码片段)
Sources → Snippets → 右键 New snippet → Ctrl + Enter 执行:
js
// 清除所有 cookie(遍历所有 cookie 并设置过期时间为过去)
document.cookie.split(';').forEach(c => { // 将 cookie 字符串按分号分割成数组
document.cookie = c.trim().split('=')[0] + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' // 设置过期时间为 1970 年(立即过期)
})
// 清除 localStorage 和 sessionStorage
localStorage.clear() // 清除本地存储的所有数据
sessionStorage.clear() // 清除会话存储的所有数据
// 查找所有绑定事件的元素(getEventListeners 是 Chrome DevTools 内置函数)
document.querySelectorAll('*').forEach(el => { // 遍历页面所有 DOM 元素
const events = getEventListeners(el) // 获取元素绑定的所有事件监听器
if (Object.keys(events).length) console.log(el, events) // 如果有事件绑定,打印元素和事件详情
})
// 获取页面所有图片尺寸($$ 是 document.querySelectorAll 的简写)
$$('img').forEach(img => console.log(img.src, img.naturalWidth, img.naturalHeight)) // 打印图片 URL 和原始尺寸
// 监控所有 fetch 请求(通过重写 fetch 函数实现)
const originalFetch = window.fetch // 保存原始 fetch 函数
window.fetch = async (...args) => { // 重写 fetch 函数
console.log('Fetch:', args[0]) // 打印请求 URL
const res = await originalFetch(...args) // 调用原始 fetch
console.log('Response:', res.status, res.url) // 打印响应状态码和 URL
return res // 返回响应对象
}
// 监控所有 XHR 请求(通过重写 XMLHttpRequest.prototype.open 实现)
const originalOpen = XMLHttpRequest.prototype.open // 保存原始 open 方法
XMLHttpRequest.prototype.open = function(method, url) { // 重写 open 方法
console.log('XHR:', method, url) // 打印请求方法和 URL
return originalOpen.apply(this, arguments) // 调用原始 open 方法
}Overrides(本地覆盖文件)
Sources → Overrides → 选择本地文件夹 → 授权
作用:将线上 JS/CSS 文件映射到本地,修改后刷新即生效。
用途:直接调试线上代码,不需要本地构建。Performance 面板
录制步骤
- 点击左上角 Record 按钮(或
Ctrl + E) - 操作页面(滚动、点击、输入、动画等)
- 点击 Stop 按钮
- 分析结果
火焰图(Main)
纵轴:调用栈(上面是调用者,下面是被调用者)
横轴:时间线(越宽耗时越长)
颜色含义:
- 蓝色(HTML 解析)→ 紫色(样式计算)→ 绿色(渲染)→ 浅蓝(绘制)
- 黄色(JS 执行)→ 红色三角 = 长任务(Long Task,> 50ms)
查看方法:
- 点击某个色块 → 下方 Details 面板显示详情
- 点击 Source 可跳转到对应代码
- 用鼠标框选放大某段时间关键指标
| 指标 | 含义 | 目标 |
|---|---|---|
| FPS | 帧率 | 稳定 60fps(绿色线) |
| CPU | CPU 使用率 | 不持续 100% |
| Net | 网络请求时间线 | 无过长请求 |
| LCP | 最大内容绘制 | < 2.5s |
| INP | 交互到下一帧绘制(替代 FID) | < 200ms |
| CLS | 累积布局偏移 | < 0.1 |
常见性能问题识别
1. Long Task(长黄条)
- JS 执行超过 50ms 阻塞主线程
- 解决:拆分为小任务(requestIdleCallback、setTimeout)
2. Layout Shift(布局偏移)
- 元素突然移动导致页面抖动
- 解决:给图片/视频预留尺寸,用 aspect-ratio
3. Recalculate Style(频繁样式重算)
- 大量读写 DOM 属性触发
- 解决:批量读写,用 requestAnimationFrame
4. 频繁 GC(垃圾回收)
- 内存中大量临时对象
- 解决:减少闭包中的大对象引用
5. FPS 掉帧(红线)
- 动画/滚动处理卡顿
- 解决:用 transform/opacity 做动画,避免 layout 触发Web Vitals 层(Chrome 96+)
Performance 面板底部有 Web Vitals 时间线,可直接查看各项指标及对应时间点:
打开方式:Performance 面板 → 录制 → 底部出现 Web Vitals 条
显示内容:
- LCP(Largest Contentful Paint):最大内容绘制
- CLS(Cumulative Layout Shift):累积布局偏移
- INP(Interaction to Next Paint):交互响应延迟(替代 FID)
点击每个指标可定位到对应的 DOM 元素和时间点💡 Web Vitals 层比 Lighthouse 更直观,因为它展示了指标发生的具体时刻和对应的页面状态。
Memory 面板(内存调试)
Heap Snapshot(堆快照)
用途:查找内存泄漏
操作步骤:
1. Memory → Heap snapshot → Take snapshot(快照 1)
2. 操作页面(点击、切换路由等)
3. Take snapshot(快照 2)
4. 对比两个快照,查看新增的对象
关注:
- 闭包(Closure)数量是否持续增长
- Detached DOM tree(已移除但未释放的 DOM)
- 事件监听器是否被正确移除Allocation Timeline(分配时间线)
用途:实时查看内存分配
操作:Record → 操作页面 → Stop
蓝色竖条 = 内存分配,越高的条分配越多
点击可查看是哪段代码分配了内存内存泄漏常见原因
js
// 1. 未清理的事件监听器(最常见)
window.addEventListener('scroll', handler) // 添加滚动事件监听器
// ✅ 组件销毁时移除(Vue 中在 onUnmounted 钩子中移除)
window.removeEventListener('scroll', handler) // 移除事件监听器,释放内存
// 2. 未清理的定时器
const timer = setInterval(fn, 1000) // 创建定时器,每秒执行一次
// ✅ 组件销毁时清除
clearInterval(timer) // 清除定时器,停止执行
// 3. 闭包引用大对象(闭包会保持对外部变量的引用)
function createHandler() {
const bigData = new Array(1000000).fill('x') // 创建一个大数组(约 1MB)
return () => console.log(bigData.length) // bigData 被闭包引用,永远不会被回收
}
// ✅ 不需要时置空引用
let handler = createHandler() // handler 持有闭包引用
handler = null // 断开引用,bigData 可被垃圾回收
// 4. 未断开的观察者(IntersectionObserver、MutationObserver 等)
const observer = new IntersectionObserver(callback) // 创建交叉观察者
observer.observe(element) // 开始观察目标元素
// ✅ 不需要时断开连接
observer.disconnect() // 停止观察,释放资源Application 面板
存储管理
| 存储 | 容量 | 生命周期 | 用途 |
|---|---|---|---|
| Local Storage | ~5MB | 持久化(手动清除) | 用户偏好、缓存 |
| Session Storage | ~5MB | 标签页关闭即清除 | 临时状态 |
| Cookies | ~4KB | 可设过期时间 | 登录状态、会话标识 |
| IndexedDB | 大容量 | 持久化 | 离线数据、大数据存储 |
| Cache Storage | 大容量 | 持久化 | Service Worker 缓存 |
操作
Local Storage / Session Storage:
- 直接双击编辑值
- 右键可删除条目
- 底部可新增条目
Cookies:
- 查看每个 cookie 的 Name、Value、Domain、Path、Expires
- 右键可删除
IndexedDB:
- 查看数据库、表、记录
- 可直接编辑/删除记录Service Worker
Application → Service Workers 面板:
- Status — 当前 SW 状态
- Update — 强制检查更新
- Unregister — 注销 SW
- Bypass for network — 绕过 SW 直接走网络(调试时很有用)
- Source — SW 源文件路径Lighthouse 审计
运行方式
- 打开 Lighthouse 面板
- 选择模式:Navigation(页面加载)或 Snapshot(当前状态)
- 选择类别:Performance / Accessibility / Best Practices / SEO / PWA
- 选择设备:Mobile(默认)/ Desktop
- 点击 Analyze page load
核心指标
| 指标 | 含义 | 目标 | 优化方向 |
|---|---|---|---|
| FCP | 首次内容绘制 | < 1.8s | 减少关键资源、预加载 |
| LCP | 最大内容绘制 | < 2.5s | 优化图片、CDN |
| TBT | 总阻塞时间 | < 200ms | 拆分长任务、延迟 JS |
| CLS | 累积布局偏移 | < 0.1 | 预留尺寸、避免动态插入 |
| SI | 速度指数 | < 3.4s | 整体加载速度 |
Vue DevTools
安装
浏览器扩展商店搜索 Vue.js devtools 安装。
核心功能
| 功能 | 说明 |
|---|---|
| Components | 组件树、props、data、computed、setup |
| Pinia / Vuex | 状态数据、时间旅行调试(回退到某个状态) |
| Timeline | 事件时间线、组件渲染性能 |
| Router | 当前路由、路由参数、导航历史 |
| Inspector | 点击页面元素 → 定位到 Vue 组件 |
常用调试操作
1. 修改组件数据
选中组件 → 右侧编辑 data/props → 实时反映到页面
2. 定位组件
点击组件左上角的定位图标 → 页面滚动到对应 DOM
3. 查看源码
点击组件名旁的文件图标 → 打开 IDE 对应文件
4. 搜索组件
顶部搜索框输入组件名
5. 性能分析
Timeline → Component events → 查看每次渲染耗时移动端调试
方案对比
| 方案 | 适用场景 | 功能 |
|---|---|---|
| vConsole | 微信/APP 内嵌 H5 | Console、Network、Elements、Storage |
| Eruda | 需要更完整调试 | vConsole 全部 + Performance、Sources |
| Chrome 远程 | Android 真机 | 完整 DevTools |
| Safari 远程 | iOS 真机 | 完整 DevTools |
vConsole
bash
npm install vconsolejs
// main.js
import VConsole from 'vconsole'
// 仅开发环境或指定条件启用
if (import.meta.env.DEV || location.search.includes('debug')) {
new VConsole()
}Eruda
html
<!-- index.html 中引入 -->
<script>
// 仅开发环境或 URL 带 debug 参数时启用
if (location.hostname === 'localhost' || location.search.includes('debug')) {
const script = document.createElement('script')
script.src = 'https://cdn.jsdelivr.net/npm/eruda'
script.onload = () => eruda.init()
document.head.appendChild(script)
}
</script>Chrome 远程调试(Android)
1. 手机开启 USB 调试(设置 → 开发者选项 → USB 调试)
2. USB 连接电脑
3. 电脑打开 chrome://inspect
4. 选择设备 → 点击 inspect
5. 完整 DevTools 打开,可调试手机上的页面Safari 远程调试(iOS)
1. iPhone:设置 → Safari → 高级 → 打开 Web 检查器
2. USB 连接 Mac
3. Mac Safari → 开发菜单 → 选择设备 → 选择页面
4. 完整 Web Inspector 打开实战调试场景
场景 1:页面白屏
排查步骤:
1. F12 → Console 看有没有红色报错
2. 有报错 → 点击堆栈跳转到源码位置
3. 没报错 → Network 看 JS/CSS 是否 404
4. 都正常 → Elements 看 #app 内是否有内容
5. 内容为空 → Vue 渲染出错,检查路由配置场景 2:接口 400/500 错误
排查步骤:
1. Network → 找到请求 → 看 Headers 中的 Request Payload
2. 对比接口文档,参数是否正确
3. 复制为 cURL → 终端执行,排除前端问题
4. 如果 cURL 也报错 → 后端问题
5. 如果 cURL 正常 → 检查 Content-Type、Authorization 头场景 3:样式不生效
排查步骤:
1. Elements → 选中元素 → Styles 面板
2. 找到目标样式 → 是否被划线(被覆盖)
3. 被覆盖 → Computed 面板看最终生效的样式来源
4. 没有出现 → 检查选择器是否匹配(特异性不够)
5. CSS 加载失败 → Network 看 CSS 文件是否 404场景 4:接口返回数据但页面没更新
排查步骤:
1. Network 确认接口返回了正确数据
2. Console 打印组件数据:
- Vue 2:$0.__vue__.$data
- Vue 3:$0.__vueParentComponent.exposed 或 $0.__vueParentComponent.setupState
3. Vue DevTools → Components → 查看对应组件的 data/props
4. 数据有了但 DOM 没更新 → 检查是否修改了非响应式数据
5. 数据也没更新 → 检查赋值逻辑、请求是否被取消场景 5:页面卡顿
排查步骤:
1. Performance → Record → 操作页面 → Stop
2. 看火焰图中是否有 Long Task(红色长条)
3. 点击长任务 → 看是哪段 JS 执行耗时
4. 常见原因:
- 大量 DOM 操作 → 用 DocumentFragment 或虚拟列表
- 频繁触发 reflow → 批量读写 DOM
- 复杂计算 → 用 Web Worker 或 requestIdleCallback场景 6:内存泄漏
排查步骤:
1. Memory → Heap snapshot → Take snapshot
2. 操作页面(切换路由、打开关闭弹窗)
3. Take snapshot → Comparison 对比
4. 查看 #Delta 列(新增对象数)
5. 关注 Detached DOM tree(已移除但未释放的 DOM 节点)
6. 常见原因:事件监听器未移除、定时器未清除、闭包引用验证调试技巧
验证断点是否生效
1. 在 Sources 面板中,点击行号设置断点
2. 执行触发断点的操作
3. 代码应该在断点处暂停,断点处会显示蓝色箭头
4. 右侧调试面板会显示当前作用域的变量值验证事件监听器
js
// 在 Console 中验证元素是否有事件绑定
getEventListeners(document.getElementById('btn'))
// 应该返回:{ click: [{ listener: f, useCapture: false, type: "click" }] }验证内存泄漏
1. Memory → Heap snapshot → Take snapshot(快照 1)
2. 操作页面(切换路由、打开关闭弹窗)
3. Take snapshot(快照 2)
4. 对比两个快照,查看 #Delta 列
5. 如果对象数持续增长且未被回收,说明存在内存泄漏常见问题
断点不生效
可能原因:
1. 代码被压缩/混淆 → 启用 Source Maps(Vite 默认开启)
2. 代码被缓存 → 禁用缓存(Network 面板 → Disable cache)
3. 断点位置错误 → 确保在可执行代码行设置断点(不是注释行)
4. 异步代码 → 使用 async/await 时,在 await 行设置断点Console 输出被清空
可能原因:
1. 页面刷新 → 勾选 Console 面板的 "Preserve log" 选项
2. 代码执行了 console.clear() → 搜索代码中的 clear 调用
3. 过滤器设置 → 检查 Console 面板的过滤器是否排除了日志性能面板录制无数据
可能原因:
1. 录制时间太短 → 录制至少 2-3 秒的操作
2. 页面未操作 → 录制期间需要进行交互(滚动、点击)
3. 浏览器扩展干扰 → 使用无痕模式录制