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