本教程介绍在 DevTools 中调试所有 JavaScript 问题的基本工作流程。请继续阅读,或观看本教程的视频版本。
重现 bug
找到一系列可一致重现错误的操作始终是调试的第一步。
- 在新标签页中打开此演示。
- 在 Number 1 框中输入
5
。 - 在 Number 2 框中输入
1
。 - 点击添加数字 1 和 2。按钮下方的标签显示
5 + 1 = 51
。结果应为6
。这就是您要修复的 bug。
在此示例中,5 + 1 的结果是 51。应该是 6。
熟悉“来源”面板界面
DevTools 可为更改 CSS、分析页面加载性能和监控网络请求等不同的任务提供许多不同的工具。您可在 Sources 面板中调试 JavaScript。
打开开发者工具并导航到 Sources 面板。
来源面板包含三个部分:
- 显示文件树的页面标签页。此处列出页面请求的每个文件。
- Code Editor 部分。在 Page 标签页中选择文件后,该文件的内容会显示在此处。
Debugger 部分。用于检查网页 JavaScript 的各种工具。
如果 DevTools 窗口较宽,默认情况下,调试程序位于 Code Editor 右侧。在本例中,作用域和监视标签页与断点、调用堆栈等一起作为可收起的部分。
使用断点暂停代码
调试此类问题的一种常用方法是在代码中插入大量 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()
语句中,您需要明确指定要检查的每个值。使用断点,DevTools 会在暂停时及时显示所有变量值。有时在您不知道的情况下,有些变量会影响您的代码。
简而言之,与 console.log()
方法相比,断点可帮助您更快地找到和修复 bug。
如果退一步思考应用的运作方式,您可以根据经验推测出,使用与 Add Number 1 and Number 2 按钮关联的 click
事件监听器时计算的和不正确 (5 + 1 = 51
)。因此,您可能需要在 click
监听器运行时暂停代码。事件监听器断点可让您完成此任务:
- 在 Debugger 部分中,点击 Event Listener Breakpoints 以展开该部分。DevTools 会显示 Animation 和 Clipboard 等可展开的事件类别列表。
- 点击 Mouse 事件类别旁边的 Expand。 DevTools 会显示鼠标事件(例如 click 和 mousedown)的列表。每个事件旁边都有一个复选框。
勾选点击复选框。DevTools 现在经过设置可以在任何
click
事件监听器运行时自动暂停。返回到演示页面,再次点击 Add Number 1 and Number 2。DevTools 会暂停演示并在 Sources 面板中突出显示一行代码。DevTools 应在此代码行暂停:
function onClick() {
如果是在其他代码行暂停,请按
Resume Script Execution,直到在正确的代码行暂停为止。
事件监听器断点只是开发者工具中提供的众多断点类型之一。值得探索所有不同的类型,因为每种类型最终都可以帮助您尽快调试不同的场景。如需了解使用每种类型的时机和方式,请参阅使用断点暂停代码。
单步调试代码
一个常见的错误原因是脚本执行顺序有误。可以通过单步调试代码一次一行地检查代码执行情况,准确找到执行顺序异常之处。��即试用:
在 DevTools 的 Sources 面板上,点击
Step into next function call,一次一行地单步调试onClick()
函数的执行。DevTools 突出显示下面这行代码:if (inputsAreEmpty()) {
依次点击
Step over next function call。DevTools 执行
inputsAreEmpty()
,但不进入其中。请注意 DevTools 是如何跳过几行代码的。这是因为inputsAreEmpty()
求值结果为 false,所以if
语句的代码块未执行。
这就是单步调试代码的基本思路。如果您看一下 get-started.js
中的代码,可以看到错误多半出在 updateLabel()
函数的某处。您可以使用另一种断点来暂停较接近极可能出错位置的代码,而不是单步调试每一行代码。
设置代码行断点
代码行断点是最常见的断点类型。如果您想在执行到某一行代码时暂停,请使用代码行断点:
查看
updateLabel()
中的最后一行代码:label.textContent = addend1 + ' + ' + addend2 + ' = ' + sum;
在代码的左侧,您可以看到这行代码的行号,即 32。点击 32。开发者工具会在 32 上方放置一个蓝色图标。这意味着这行代码上有一个代码行断点。现在,开发者工具始终会在执行此代码行之前暂停。
依次点击
继续执行脚本。脚本将继续执行,直到第 32 行。在第 29 行、第 30 行和第 31 行上,DevTools 会在addend1
、addend2
和sum
的声明旁边内嵌显示其值。
在此示例中,DevTools 会在第 32 行代码行断点处暂停。
检查变量值
addend1
、addend2
和 sum
的值疑似有问题。它们使用英文引号引起来,这意味着它们是字符串。这个假设有助于说明错误的原因。现在可以收集更多信息。开发者工具提供了许多用于检查变量值的工具。
方法 1:检查范围
在某代码行暂停时,Scope 标签页会显示在执行此时刻定义的局部和全局变量,以及各变量值。其中还会显示闭包变量(如果适用)。如果不在任何代码行暂停,则 Scope 标签页为空。
双击变量值可进行编辑。
方法 2:监视表达式
Watch 标签页可让您监视变量值随时间变化的情况。监视不仅限于变量。您可以在监视标签页中存储任何有效的 JavaScript 表达式。
立即试用:
- 点击观看标签页。
- 依次点击 添加监视表达式。
- 输入
typeof sum
。 - 按 Enter 键。开发者工具显示
typeof sum: "string"
。冒号右侧的值是表达式的结果。
此屏幕截图显示了创建 typeof sum
监视表达式后的监视标签页(右下角)。
正如猜想,sum
的求值结果本应是数字,而实际结果却是字符串。现在已确定这就是错误的原因。
方法 3:控制台
除了查看 console.log()
消息之外,您还可以使用控制台对任意 JavaScript 语句求值。对于调试,您可以使用控制台测试错误的潜在解决方法。立即试用:
- 如果您尚未打开 Console 抽屉式导航栏,请按 Escape 将其打开。该导航栏将在 DevTools 窗口底部打开。
- 在控制台中,输入
parseInt(addend1) + parseInt(addend2)
。此语句有效,因为您会在特定代码行暂停,其中addend1
和addend2
在范围内。 - 按 Enter 键。开发者工具会评估该语句并输出
6
,这是您预期演示版生成的结果。
此屏幕截图显示了对 parseInt(addend1) + parseInt(addend2)
求值后的 Console 抽屉式导航栏。
应用修复
您已找到修正错误的方法。接下来就是尝试通过编辑代码并重新运行演示来使用修正方法。您无需离开 DevTools 就能应用修正。您可以直接在 DevTools 界面中修改 JavaScript 代码。立即试用:
- 依次点击 继续执行脚本。
- 在 Code Editor 中,将第 31 行
var sum = addend1 + addend2
替换为var sum = parseInt(addend1) + parseInt(addend2)
。 - 按 Command + S (Mac) 或 Control + S(Windows、Linux)保存更改。
- 点击 停用断点。 其颜色会变为蓝色,表示已启用。完成此设置后,开发者工具会忽略您已设置的任何断点。
- 尝试使用不同的值运行演示。演示现在可正确计算。
后续步骤
本教程仅介绍两种设置断点的方法。DevTools 还提供了许多其他方法,包括:
- 仅在满足您指定的条件时触发的条件断点。
- 发生已捕获或未捕获异常时触发的断点。
- 当请求的网址与您提供的子字符串匹配时触发的 XHR 断点。
如需了解何时以及如何使用每种类型,请参阅使用断点暂停代码。
有几个代码单步执行控件未在本教程中进行说明。如需了解详情,请参阅单步调试代码行。