2、前端调试技巧:断点调试(Breakpoints)、条件断点、DOM断点、事件监听器断点、XHR/Fetch断点

调试,说白了就是给代码看病。你写了一大段逻辑,结果页面白屏了,或者数据死活不对。这时候怎么办?console.log 打满天下?我以前也这么干,直到有一次在线上环境忘了删 log,把用户控制台刷成了瀑布流……嗯,从那以后我老老实实学断点。

断点调试是 Chrome DevTools 里最核心的技能。我敢说,你把这五种断点玩熟了,至少能省下一半的排查时间。咱们一个一个来。

2.1 基础断点(Breakpoints)

这是最基础的,也是你最先要掌握的。在 Sources 面板里,找到你要调试的 JS 文件,点击行号左侧,就会出现一个蓝色箭头。这就是断点。

页面运行到这一行时,会自动暂停。你可以看到当前所有变量的值,也可以一步步往下走。

核心操作:

  • F8:继续执行,直到下一个断点
  • F10:单步跳过,不进入函数内部
  • F11:单步进入,会钻进函数里看细节
  • Shift + F11:跳出当前函数

我个人习惯是:先大致定位问题区域,打一个断点。然后按 F10 快速过一遍流程。如果发现某个函数返回值不对劲,再按 F11 钻进去看。

小技巧: 你可以在断点上右键,选择「Edit breakpoint」。这里可以写一个表达式,只有表达式为 true 时才会暂停。比如你只关心循环到第 10 次的情况,就写 i === 10

2.2 条件断点(Conditional Breakpoints)

这个太实用了。你想想看,一个 for 循环跑了 1000 次,你总不能每次都停下来看吧?

右键点击行号,选择「Add conditional breakpoint」。输入条件表达式,比如 user.id === 1024。只有满足条件时,代码才会暂停。

// 假设你在调试这段代码
for (let i = 0; i < users.length; i++) {
  const user = users[i];
  // 在这里打条件断点:user.role === 'admin'
  processUser(user);
}

我在项目中遇到过一个问题:某个用户的数据总是渲染异常,但其他用户都正常。用条件断点直接定位到那个用户的 ID,一下子就看到了数据格式的差异。比一条条 log 翻效率高太多了。

注意: 条件表达式里不要写太复杂的逻辑,也不要调用异步函数。否则调试器会卡住,甚至导致页面崩溃。我曾经写了个 await fetch() 进去……嗯,页面直接挂了。

2.3 DOM 断点(DOM Breakpoints)

这个断点不是打在 JS 代码上的,而是打在 DOM 元素上的。你想想看,有时候页面上的某个元素突然消失了,或者样式被改了,你根本不知道是哪段代码干的。

在 Elements 面板里,选中你要监控的元素,右键 → Break on → 选择一种类型:

类型 触发时机 适用场景
Subtree modifications 子节点被增删改时 列表项被动态添加或移除
Attribute modifications 元素的属性(如 class、style)被修改时 某个元素的样式突然变了
Node removal 元素本身被移除时 元素莫名其妙消失了

我记得有一次,一个弹窗组件在点击后总是闪一下就消失。我怀疑是某个定时器把它移除了,但翻遍代码都找不到。最后用 DOM 断点监控了弹窗的 Node removal,一触发就直接定位到了罪魁祸首——一个清理函数被错误地绑定了两次。

建议: DOM 断点特别适合排查「谁动了我的元素」这类问题。配合 Call Stack 面板,你能看到完整的调用链,包括是哪个事件触发的、哪个函数执行的。

2.4 事件监听器断点(Event Listener Breakpoints)

这个功能在 Sources 面板的右侧。点开「Event Listener Breakpoints」,你会看到一长串事件类型:click、mouseover、scroll、keydown……

勾选某个事件后,只要页面上有任何代码触发了这个事件,调试器就会自动暂停。注意,是所有代码,包括第三方库的。

举个例子:你发现点击某个按钮后,页面跳转了。但你找不到是哪个事件绑定的。勾选 click 事件断点,然后点击按钮。调试器会停在触发 click 的那一行代码上。你就能看到是哪个函数在处理这个点击。

常用场景:

  • 排查点击事件冒泡导致的意外行为
  • 定位第三方库中的事件绑定
  • 检查键盘快捷键是否被正确触发

我个人习惯是:先勾选所有鼠标事件,然后快速操作页面。如果某个操作触发了断点,再缩小范围到具体的事件类型。这样能快速找到「谁在监听我的操作」。

2.5 XHR / Fetch 断点(XHR/Fetch Breakpoints)

这个断点专门用来调试网络请求。在 Sources 面板右侧,找到「XHR/Fetch Breakpoints」。点击加号,输入一个 URL 关键字。

比如你输入 /api/user,那么所有包含这个关键字的请求(无论是 XHR 还是 Fetch)都会触发断点。调试器会停在发起请求的那一行代码上。

// 假设你在调试这段代码
fetch('/api/user/profile', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ id: 1024 })
})
.then(res => res.json())
.then(data => {
  // 你想看看 data 到底是什么
});

在断点触发时,你可以查看请求的 headers、body,以及后续的响应数据。我经常用它来排查「请求发了但没收到响应」或者「响应数据格式不对」的问题。

避坑指南: 我曾经在调试时输入了 / 作为关键字,结果所有请求都触发了断点……页面直接卡死。建议关键字尽量精确,比如具体的接口路径或参数名。

2.6 综合实战:一个真实场景

假设你遇到一个问题:用户点击「提交订单」按钮后,页面没有任何反应。控制台也没有报错。你怎么排查?

  1. 先打事件监听器断点:勾选 click 事件。点击按钮,看看到底有没有触发 click。
  2. 如果触发了:在 Sources 里找到对应的处理函数,打一个基础断点。按 F10 一步步走,看逻辑走到哪一步停了。
  3. 如果没触发:可能是按钮被禁用了,或者被其他元素遮挡了。用 DOM 断点监控按钮的 attribute modifications,看谁改了它的 disabled 属性。
  4. 如果请求没发出去:在 XHR/Fetch 断点里加上接口关键字。点击按钮,看请求是否被发起。如果没发起,说明请求代码根本没执行到。
  5. 如果请求发了但没响应:在 Network 面板里看请求详情。状态码、响应体、请求头,一个一个排查。

你看,这五种断点组合起来,几乎能覆盖前端调试的 90% 场景。不用再靠 console.log 瞎猜了。

最后说一句: 调试不是找 bug,而是理解代码的运行过程。断点让你能「慢放」代码的执行,看到每一帧的状态。多用几次,你会爱上这种感觉的。