调试 JavaScript

Sofia Emelianova
Sofia Emelianova

本教程介绍了在开发者工具中调试任何 JavaScript 问题的基本工作流程。请继续阅读或观看本教程的视频版本。

重现 bug

找到一系列可一致重现 bug 的操作始终是调试的第一步。

  1. 在新标签页中打开演示版应用
  2. 第 1 点框中输入 5
  3. 第 2 项框中输入 1
  4. 点击 Add Number 1 and Number 2(添加数字 1 和数字 2)。按钮下方的标签显示 5 + 1 = 51。结果应为 6。这就是您要修复的 bug。

5 + 1 的结果是 51。应该是 6。

在本例中,5 + 1 的结果为 51。应该是 6。

熟悉“Sources”面板界面

开发者工具为不同的任务提供了许多不同的工具,例如更改 CSS、分析页面加载性能以及监控网络请求。Sources 面板供您调试 JavaScript。

  1. 打开开发者工具并前往 Sources 面板。

    “来源”面板。

来源面板包含三个部分:

“来源”面板的 3 个部分。

  1. 包含文件树的页面标签页。此处列出了页面请求的每个文件。
  2. 代码编辑器部分。在 Page 标签页中选择文件后,该文件的内容会显示在此处。
  3. Debugger 部分。用于检查网页 JavaScript 的各种工具。

    如果开发者工具窗口较宽,默认情况下,Debugger 位于代码编辑器的右侧。在这种情况下,ScopeWatch 标签页会将 BreakpointsCall stack 和其他作为可收起的部分联接。

宽窗口右侧的 Debugger。

使用断点暂停代码

调试此类问题的一种常用方法是在代码中插入大量 console.log() 语句,以便在脚本执行时检查值。例如:

function updateLabel() {
  var addend1 = getNumber1();
  console.log('addend1:', addend1);
  var addend2 = getNumber2();
  console.log('addend2:', addend2);
  var sum = addend1 + addend2;
  console.log('sum:', sum);
  label.textContent = addend1 + ' + ' + addend2 + ' = ' + sum;
}

console.log() 方法可以完成工作,但断点可以更快完成工作。通过断点,您可以在代码执行过程中暂停代码,并在该时刻检查所有值。与 console.log() 方法相比,断点具有一些优势:

  • 使用 console.log() 时,您需要手动打开源代码,找到相关代码,插入 console.log() 语句,然后重新加载页面,才能在控制台中查看这些消息。使用断点,您甚至无需了解代码的结构即可暂停相关代码。
  • console.log() 语句中,您需要明确指定要检查的每个值。使用断点,开发者工具会及时显示所有变量的值。 有时,有些变量会影响您的代码,而您甚至不知道这些变量。

简而言之,与 console.log() 方法相比,断点可以帮助您更快地查找和修复 bug。

如果您后退一步仔细想想应用的工作原理,可以有根据地猜测,在与 Add Number 1 and Number 2 按钮关联的 click 事件监听器中计算了错误总和 (5 + 1 = 51)。因此,您可能需要在 click 监听器执行前后暂停代码。事件监听器断点可让您做到这一点:

  1. Debugger 部分中,点击 Event Listener Breakpoints 以展开该部分。开发者工具会显示一系列可展开的事件类别,例如动画剪贴板
  2. 鼠标事件类别旁边,点击 arrow_right 展开。 开发者工具会显示鼠标事件列表,例如 clickmousedown。每个事件旁边都有一个复选框。
  3. 选中 click 复选框。开发者工具现在已设置为在执行任何 click 事件监听器时自动暂停。

    “点击”复选框处于选中状态。

  4. 返回演示,再次点击 Add Number 1 and Number 2(添加编号 1 和编号 2)。开发者工具会暂停演示,并在 Sources 面板中突出显示一行代码。在以下代码行代码中,开发者工具应暂停:

    function onClick() {
    

    如果是在其他代码行上暂停,请按恢复恢复脚本执行,直到暂停位置正确行。

事件监听器断点只是开发者工具中提供的众多断点类型之一。您有必要探索所有不同的类型,因为每种类型最终都可帮助您尽快调试不同的场景。如需了解每种类型的适用情形和使用方式,请参阅使用断点暂停代码

逐步执行代码

导致 bug 的一个常见原因是脚本执行顺序有误。通过单步调试代码,您可以一次一行地了解代码的执行情况,并弄清楚代码的执行顺序与预期不同。立即试用:

  1. 在开发者工具的 Sources 面板上,点击 step_into Step into next function call(单步执行),以一次一行的形式逐步执行 onClick() 函数。DevTools 突出显示了下面这行代码:

    if (inputsAreEmpty()) {
    
  2. 点击 Step over next 函数调用 step_over

    开发者工具会执行 inputsAreEmpty(),而不会进入它。请注意开发者工具如何跳过几行代码。这是因为 inputsAreEmpty() 的求值结果为 false,所以 if 语句的代码块并未执行。

这就是单步调试代码的基本思路。如果查看 get-started.js 中的代码,您会发现 bug 很可能位于 updateLabel() 函数中的某个位置。您可以使用另一种类型的断点来暂停靠近 bug 可能位置的代码,而不是单步调试每一行代码。

设置代码行断点

代码行断点是最常见的断点类型。如果您想在执行到某一行代码时暂停,请使用代码行断点:

  1. 查看 updateLabel() 中的最后一行代码:

    label.textContent = addend1 + ' + ' + addend2 + ' = ' + sum;
    
  2. 在这行代码的左侧,您可以看到这行代码的行号,即 32。点击 32。开发者工具会在 32 上方放置一个蓝色图标。这意味着该行上有一个代码行断点。现在,开发者工具总是会在执行此代码行之前暂停。

  3. 点击继续 继续执行脚本。脚本会继续执行,直到第 32 行。在第 29、30 和 31 行,DevTools 会在其声明旁边显示 addend1addend2sum 的值。

开发者工具暂停在第 32 行代码行断点处。

在此示例中,开发者工具会在第 32 行代码行断点处暂停。

检查变量值

addend1addend2sum 的值看起来很可疑。它们用英文引号引起来,这意味着它们是字符串。这是一个很好的假设,可以很好地解释 bug 的原因。现在可以收集更多信息了。开发者工具提供了许多用于检查变量值的工具。

方法 1:检查范围

暂停某行代码时,Scope 标签页会显示执行过程中定义的局部和全局变量,以及每个变量的值。其中还会显示闭包变量(如果适用)。如果您未在某行代码上暂停,则 Scope 标签页为空。

双击变量值即可进行修改。

“Scope”窗格。

方法 2:监视表达式

通过 Watch 标签页,您可以监控变量的值随时间的变化。Watch 不仅限于变量。您可以将任何有效的 JavaScript 表达式存储在 Watch 标签页中。

立即试用:

  1. 点击观看标签页。
  2. 点击 add 添加监视表达式
  3. 输入 typeof sum
  4. Enter 键。开发者工具显示 typeof sum: "string"。冒号右侧的值是表达式的结果。

“Watch Expression”窗格

此屏幕截图显示了创建 typeof sum 监视表达式后的 Watch 标签页(右下角)。

和猜测一样,sum 的求值结果本应是数字,而实际结果却是字符串。现在,您已经确认这是错误的原因。

方法 3:控制台

除了查看 console.log() 消息之外,您还可以使用控制台对任意 JavaScript 语句求值。在调试方面,您可以使用控制台测试 bug 的潜在修复方法。立即试用:

  1. 如果您尚未打开控制台抽屉,请按 Esc 键将其打开。它会在开发者工具窗口底部打开。
  2. 在控制台中,输入 parseInt(addend1) + parseInt(addend2)。此语句之所以有效,是因为您在 addend1addend2 在范围内的一行代码上暂停。
  3. Enter 键。开发者工具会评估语句并输出 6,这是您希望演示版生成的结果。

对范围内的变量求值后的控制台抽屉。

此屏幕截图显示了对 parseInt(addend1) + parseInt(addend2) 求值后的 Console 抽屉式导航栏。

应用修正

您已找到该 bug 的修复程序。接下来就是尝试通过修改代码并重新运行演示来尝试修复方法。您无需离开开发者工具即可应用修正。您可以直接在开发者工具界面中修改 JavaScript 代码。立即试用:

  1. 点击继续 继续执行脚本
  2. 代码编辑器中,将第 31 行 var sum = addend1 + addend2 替换为 var sum = parseInt(addend1) + parseInt(addend2)
  3. Command + S (Mac) 或 Ctrl + S(Windows、Linux)以保存更改。
  4. 点击 label_off 停用断点。 其颜色会变为蓝色,表示处于活动状态。完成此设置后,开发者工具会忽略您已设置的任何断点。
  5. 尝试使用不同的值进行演示。演示现在可正确计算。

后续步骤

本教程仅介绍了两种设置断点的方法。开发者工具还提供了许多其他方式,包括:

  • 仅在满足您指定的条件时触发的条件断点。
  • 已捕获或未捕获异常时触发的断点。
  • 当请求的网址与您提供的子字符串匹配时触发的 XHR 断点。

如需了解每种类型的适用情形和使用方式,请参阅使用断点暂停代码

有几个代码单步执行控件在本教程中未作说明。如需了解详情,请参阅单步调试代码行