在 Chrome DevTools 中调试 JavaScript 入门
本交互式教程循序渐进地教您在 Chrome DevTools 中调试 JavaScript 的基本工作流程。 虽然教程介绍的是如何调试一种具体问题,但您学到的一般工作流程对调试各种类型的 JavaScript 错误均有帮助。
如果您使用 console.log()
来查找和修正代码中的错误,可以考虑改用本教程介绍的工作流程。 其速度快得多,也更有效。
重现错误
重现错误始终是调试的第一步。“重现错误”是指找到一系列总是能导致错误出现的操作。
您可能需要多次重现错误,因此要尽量避免任何多余的步骤。
请按照以下说明重现您要在本教程中修正的错误。
- 点击 Open Demo。演示页面在新标签中打开。
- 在演示页面上,输入
5
作为 Number 1。 - 输入
1
作为 Number 2。 - 点击 Add Number 1 and Number 2。
- 查看输入和按钮下方的标签。上面显示的是
5 + 1 = 51
。
啊呜。这个结果是错误的。正确结果应为 6
。这就是您要修正的错误。
使用断点暂停代码
DevTools 让您可以暂停执行中的代码,并对暂停时刻的所有变量值进行检查。 用于暂停代码的工具称为断点。 立即试一试:
- 按
Command+Option+I
(Mac) 或Ctrl+Shift+I
(Windows、Linux)在演示页面上打开 DevTools。 - 点击 Sources 标签。
- 点击 Event Listener Breakpoints 将该部分展开。DevTools 显示一个包含 Animation 和 Clipboard 等可展开事件类别的列表。
- 在 Mouse 事件类别旁,点击 Expand Expand 图标。DevTools 显示一个包含 click 等 Mouse 事件的列表,事件旁有相应的复选框。
- 选中 click 复选框。
DevTools 在演示页面上打开,Sources 面板获得焦点,click
事件侦听器断点处于启用状态。 如果 DevTools 窗口较大,则 Event Listener Breakpoints 窗格位于右侧,而不是像屏幕截图中那样位于左下方。
- 返回至演示页面,再次点击 Add Number 1 and Number 2。DevTools 暂停演示并在 Sources 面板中突出显示一行代码。 DevTools 突出显示的是下面这行代码:
function onClick() {
当您选中 click 复选框时,就是在所有 click
事件上设置了一个基于事件的断点。 点击了任何节点,并且该节点具有 click
处理程序时,DevTools 会自动暂停在该节点 click
处理程序的第一行。
这不过是 DevTools 提供的众多断点类型中的一种。应使用的断点类型取决于您要调试的问题类型。
单步调试代码
一个常见的错误原因是脚本执行顺序有误。 可以通过单步调试代码一次一行地检查代码执行情况,准确找到执行顺序异常之处。立即试一试:
- 在 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
。DevTools 会在32
上放置一个蓝色图标。 这意味着这行代码上有一个代码行断点。 DevTools 现在总是会在执行这行代码之前暂停。 - 点击 Resume script execution 继续执行脚本。 脚本继续执行,直至到达您设置了断点的代码行。
- 看一下
updateLabel()
中已执行的代码行。
DevTools 打印输出 addend1
、addend2
和 sum
的值。
sum
的值疑似有问题。其求值结果本应是数字,而实际结果却是字符串。 这可能就是造成错误的原因。
检查变量值
另一种常见的错误原因是,变量或函数产生的值异常。 许多开发者都利用 console.log()
来了解值随时间变化的情况,但 console.log()
可能单调乏味而又效率低下,原因有两个。 其一,您可能需要手动编辑大量调用 console.log()
的代码。 其二,由于您不一定知晓究竟哪一个变量与错误有关,因此可能需要对许多变量进行记录。
DevTools 为 console.log()
提供的其中一个替代工具是监视表达式。可以使用监视表达式来监视变量值随时间变化的情况。顾名思义,监视表达式的监视对象不仅限于变量。您可以将任何有效的 JavaScript 表达式存储在监视表达式中。 立即试一试:
- 在 DevTools 的 Sources 面板上,点击 Watch。该部分随即展开。
- 点击 Add Expression 添加表达式。
- 键入
typeof sum
。 - 按 Enter。DevTools 显示
typeof sum: "string"
。冒号右侧的值就是监视表达式的结果。
创建 typeof sum
监视表达式后的“监视表达式”窗格(右下方)。 如果 DevTools 窗口较大,则“监视表达式”窗格位于右侧,Event Listener Breakpoints 窗格的上方。
正如猜想的那样,sum 的求值结果本应是数字,而实际结果却是字符串。 这就是演示页面错误的原因。
DevTools 为 console.log()
提供的另一个替代工具是 Console。可以使用 Console 对任意 JavaScript 语句求值。开发者通常利用 Console 在调试时覆盖变量值。在您所处的情况下,Console 可帮助您测试刚发现的错误的潜在解决方法。 立即试一试:
- 如果您尚未打开 Console 抽屉,请按 Escape 将其打开。 它会在 DevTools 窗口底部打开。
- 在 Console 中,键入
parseInt(addend1) + parseInt(addend2)
。 - 按 Enter。DevTools 对语句求值并打印输出
6
,即您预料演示页面会产生的结果。
对 parseInt(addend1) + parseInt(addend2)
求值后的 Console 抽屉。
应用修正
您已找到错误的潜在解决方法。剩下的工作就是编辑代码后重新运行演示页面来测试修正效果。 您不必离开 DevTools 就能应用修正。 您可以直接在 DevTools UI 内编辑 JavaScript 代码。 立即试一试:
- 在 DevTools 的 Sources 面板上的代码编辑器中,将
var sum = addend1 + addend2
替换为var sum = parseInt(addend1) + parseInt(addend2);
。它就是您当前暂停位置上面那行代码。 - 按 Command+S (Mac) 或 Ctrl+S(Windows、Linux)保存更改。代码的背景色变为红色,这表示在 DevTools 内更改了脚本。
- 点击 Deactivate breakpoints 停用断点。它变为蓝色,表示处于活动状态。 如果进行了此设置,DevTools 会忽略您已设置的任何断点。
- 点击 Resume script execution 继续执行脚本。
- 使用不同的值测试演示页面。现在演示页面应能正确计算求和。
切记,此工作流程只对运行在浏览器中的代码应用修正。 它不会为所有运行您的页面的用户修正代码。 要实现该目的,您需要修正运行在提供页面的服务器上的代码。
后续步骤
恭喜!现在您已掌握了在 DevTools 中调试 JavaScript 的基础知识。
本教程只向您介绍了两种设置断点的方法。DevTools 还提供了许多其他方法,其中包括:
- 仅在满足您指定的条件时触发的条件断点。
- 发生已捕获或未捕获异常时触发的断点。
- 当请求的网址与您提供的子字符串匹配时触发的 XHR 断点。
如何设置断点
利用断点暂停 JavaScript 代码,并调查该特定时刻的变量值和调用堆栈。断点设置完成后,您就可以了解如何逐步执行代码并在如何单步调试代码中调查您的变量和调用堆栈。
在特定代码行中设置断点
当您知道自己想要调查的语句时,在特定代码行中设置断点就大有用处。 例如,如果您的登录工作流没有如期工作,并且在您的代码中只有一个处理此登录的函数,则假设错误可能位于该函数中是正确的。此情形下,在该函数的第一行添加断点是行得通的。
当您在代码行中设置断点时,代码始终会在该代码行处暂停,直至您删除、停用此断点或将其设置为有条件的断点为止。
要在特定代码行中设置断点,首先请打开 Sources 面板,然后从左侧的 File Navigator 窗格中选择脚本。
如果您看不到 File Navigator,请按 Toggle file navigator 按钮(隐藏/显示 file navigator 按钮)。
提示:如果您在处理压缩过的代码,请按 pretty print 按钮(pretty print 按钮)使代码可读。
沿着源代码的左侧,您可以看到行号。此区域称为行号边线。 在行号边线中点击可在该行代码上添加一个断点。
如果一个表达式由多个行隔开,且您在此表达式的中间放置了一个行断点,则 DevTools 将在下一个表达式中设置此断点。例如,如果您尝试在以下屏幕截图中的第 4 行中设置断点,则 DevTools 会将此断点放置到第 6 行。
创建一个有条件的行号断点
有条件的断点仅在满足您指定的条件时触发。
右键单击一个还没有断点的行号,并按 Add conditional breakpoint 可创建一个有条件的断点。 如果您已在行代码中添加了一个断点,并想为该断点设置条件,则右键点击并按 Edit breakpoint。
在文本字段中输入您的条件并按 Enter。
有条件的断点呈金色。
删除或停用行号断点
如果您要暂时忽略一个断点,则停用它。 在行号边线中右键点击并选择 Disable breakpoint。
如果您不再需要断点,则删除它。在行号边线中右键点击并选择 Remove breakpoint。
您也可以从一个位置管理跨所有脚本的所有行号断点。 此位置就是 Sources 面板上的 Breakpoints 窗格。
若要从 Breakpoints 窗格 UI 中删除断点,请右键点击它并选择 Remove breakpoint。
如需从此窗格停用断点,则停用它的复选框。
如需停用所有断点,则中此窗格中右键点击,并选择 Deactivate breakpoints。 这可与 Disable All Breakpoints 选项产生相同的效果。
您也可以通过按同样位于 Sources 面板上的 deactivate breakpoints 按钮停用所有断点。
有几个代码单步执行控件在本教程中未予说明。 请点击以下链接,了解有关它们的更多信息。
如何单步调试代码
通过每次执行一个代码行或一个函数,您可以观察数据和页面中的变化,准确了解正在发生什么。您还可以修改脚本使用的数据值,您甚至可以修改脚本本身。
为什么此变量值是 20
而不是 30
?为什么该代码行看上去没什么效果?为什么此标志在应为 false
的时候成为 true
? 每个开发者都面临这些问题,逐步执行代码可了解问题所在。
设置断点后,返回此页面,并正常地使用它,直到达到某个断点。这将暂停页面上的所有 JavaScript,焦点转向“DevTools Sources”面板,并突出显示断点。现在,您可以有选择性地执行代码并逐步检查其数据。
步骤的操作
所有步骤选项均通过边栏中的可点击图标断点按钮栏表示,但也可以通过快捷键触发。下面是简要介绍:
- Resume:继续执行直到下一个断点。如果没有遇到断点,则继续正常执行。
- Long Resume:继续执行,将断点停用
500
毫秒。便于暂时跳过断点,否则会持续暂停执行代码,例如,循环内的断点。点击并按住 Resume,直到展开以显示操作。 - Step Over:不管下一行发生什么都会执行,并跳转到下一行。
- Step Into:如果下一行包含一个函数调用,Step Into 将跳转并在其第一行暂停该函数。
- Step Out:函数调用后,执行当前函数剩余部分,然后在下一个语句暂停。
- Deactivate breakpoints:暂时停用所有断点。用于继续完整执行,不会真正移除断点。再次点击以重新激活断点。
- Pause on exceptions:在发生异常时,自动暂停执行代码。
使用 step into 作为典型的“一次一行”操作,因为它确保只有一个语句被执行,无论您进入或离开哪些函数。
当您怀疑未捕获的异常正在引发问题,但不知道异常在哪里时,使用 Pause on exceptions。启用此选项后,您可以通过点击 Pause On Caught Exceptions 复选框优化它;在此情况下,仅当发生需要特别处理的异常时执行才会暂停。
按作用域查看属性
当您暂停脚本时,Scope 窗格会显示在该时刻当前已定义的所有属性。
在以下屏幕截图中,此窗格用蓝色突出显示。
Scope 窗格只有在脚本暂停时才会填充信息。页面运行时,Scope 窗格不含任何信息。
Scope 窗格显示在 local
、closure
和 global
级别定义的属性。
如果某个属性旁有“Carat”图标,这意味着此属性指代一个对象。点击“Carat”图标可展开对象并查看其属性。
有时这些属性的显示会变暗。例如,在以下屏幕截图中,属性 constructor
比 confirm
属性暗淡。
深颜色属性可以计数。浅颜色、显示暗淡的属性则不可计数。 如需了解详细信息,请参阅以下 Stack Overflow 主题:Chrome 开发者工具 Scope 面板中的颜色有何含义?
调用堆栈
在靠近边栏顶部的位置是 Call Stack 部分。在断点处代码暂停时,调用堆栈以倒序形式显示将代码带到该断点的执行路径。这不但有助于了解执行现在所在位置,还有助于了解代码的执行路径,这是进行调试的一个重要因素。
index.html
文件中位于第 50
行的一个初始 onclick
事件调用了位于 dgjs.js
。 JavaScript 文件第 18
行的 setone()
函数,后者接着调用了位于同一文件第 4
行的 setall()
函数,执行在当前断点处暂停。
启用异步调用堆栈
启用异步调用堆栈功能可提高执行异步函数调用的透明度。
- 打开 DevTools 的 Sources 面板。
- 在 Call Stack 窗格上,启用 Async 复选框。
以下视频包含一个展示异步调用堆栈功能的简单脚本。 在此脚本中,第三方库用于选择一个 DOM 元素。 一个名为 onClick
的函数被注册为此元素的 onclick
事件处理程序。 无论何时调用 onClick
,它都会循序调用一个名为 f
的函数,该函数通过 debugger
关键字强制脚本暂停。
在此视频中,触发了一个断点并展开了调用堆栈。堆栈中只有一个调用:f
。 然后,启用异步调用堆栈功能,脚本继续执行,并再次触发断点和展开调用堆栈。此时,调用堆栈包含 f
之前的所有调用,包括第三方内容库调用和 onClick
调用。首次调用该脚本时,调用堆栈中只有一个调用。 第二次调用脚本时,有四个调用。简言之,异步调用堆栈功能可提高完整的异步函数调用堆栈的可视性。
给函数命名以提高调用堆栈可读性
匿名函数使调用堆栈很难阅读。为函数命名以提高可读性。
以下两个屏幕截图中的代码段功能效果相同:代码功能并不重要,重要的是第一个屏幕截图中的代码使用匿名函数,而第二个屏幕截图中的代码使用已命名的函数。
在第一个屏幕截图的调用堆栈中,前两个函数均标明 (anonymous function
)。 在第二个屏幕截图中,前两个函数已命名,从而让您更容易了解程序流的大致情况。在处理大量的脚本文件(包括第三方内容库和框架)时,您的调用堆栈为五个或者十个调用深,在函数已命名后,理解调用堆栈流要容易得多。
含匿名函数的调用堆栈:
含已命名函数的调用堆栈:
将第三方代码设置为黑箱
将脚本文件设置为黑箱以忽略来自调用栈的第三方文件。
设置为黑箱之前:
设置为黑箱之后:
如需将文件设置为黑箱:
打开 DevTools Settings。
在左侧的导航菜单中,点击 Blackboxing。
- 点击 Add pattern。
- 在 Pattern 文本字段中,输入您想要从调用堆栈排除的文件名模式。 DevTools 将排除与该模式匹配的任意脚本。
- 在文本字段右侧的下拉菜单中,选择 Blackbox 以执行脚本文件,但从调用堆栈排除调用,或选择 Disabled 以阻止执行文件。
- 点击 Add 保存。
下次运行此页面并触发断点时,DevTools 将使函数调用不出现在来自调用堆栈的已设置为黑箱的脚本中。
数据操作
代码执行暂停时,您可以观察和修改其正在处理的数据。这对于尝试追踪一个看上去有错误值的变量或没有如期收到的传递参数很关键。
通过点击 Show/Hide drawer 显示 Console 抽屉显示/隐藏抽屉或按 ESC.在执行步骤时打开控制台,您现在可以:
- 输入变量的名称以在当前函数范围中查看其当前值
- 输入一个 JavaScript 分配语句以更改此值
尝试修改值,然后继续执行以查看它如何改变您的代码的结果,以及它是否如期运行。
我们发现参数 dow
的值当前为 2
,但在继续执行前将其手动更改为 3
。
实时编辑
观察并暂停执行代码有助于您查找错误,而实时编辑让您可以快速预览更改,无需重新加载。
如需实时编辑脚本,只需在执行步骤时点击“Sources”面板的编辑器部分。在编辑器中进行所需的更改,然后按 Ctrl+S(或在 Mac 上按 Cmd+S)提交此更改。此时,整个 JS 文件将作为补丁程序进入 VM,并且所有函数定义都将更新。
现在,您可以继续执行;已修改的脚本将替代原始脚本执行,并且您可以观察您的更改效果。
我们怀疑参数 dow
在被传递到函数 setone()
时,在任何情况下都会增加 1
,也就是说,收到的值 dow<
在应为 0
时却为 1
,在应为 1
时却为 2
,等等。为了快速测试递减的传递值是否确认这是一个问题,我们在函数的开头添加第 17
行,并按 Ctrl + S 键提交并继续。
管理线程执行
使用 Sources 面板上的 Threads 窗格可暂停、进入以及检查其他线程,例如服务工作线程或网络工作线程。
为展示 Threads 窗格,此部分使用了以下演示:网络工作线程基本示例。
如果您打开应用上的 DevTools,就能发现 main 脚本位于 main.js
中:
网络 worker 脚本位于 worker.js
中:
Main 脚本侦听对 Multiply number 1 或 Multiply number 2 输入字段做出的更改。 侦听到更改时,main 脚本立即向网络工作线程发送一则消息,内含这两个需要相乘的数值。 网络工作线程执行完乘法运算后将结果返回给 main 脚本。
假定您在 main.js
中设置了一个在第一个数字发生变化时触发的断点:
并且您还在 worker.js
中设置了一个在工作线程收到消息时触发的断点:
在此应用的 UI 触发这两个断点时修改第一个数字。
在 Threads 窗格中,蓝色箭头指示的是当前选定的线程。 例如,在上面的屏幕截图中,选定的是 Main 线程。
DevTools 所有用于单步调试代码(继续或暂停脚本执行、单步执行下一函数调用、进入并单步执行下一函数调用等)的控件都与该线程有关。换言之,如果您在 DevTools 显示类似以上屏幕截图的内容时按 Resume script execution 按钮,Main 线程会继续执行,但网络工作线程仍将暂停。Call Stack 和 Scope 部分同样只显示 Main 线程的信息。
如果您想为网络工作线程单步调试代码,或查看其作用域和调用堆栈信息,只需在 Threads 窗格中点击其标签,使其旁边出现蓝色箭头。以下屏幕截图显示的是选择工作线程后调用堆栈和作用域信息的变化情况。同样,如果您要按任何一个单步调试代码按钮(继续执行脚本、单步执行下一函数调用等),该操作将只与工作线程有关。Main 线程不受影响。
特别声明:本文内容来源于:https://developers.google.com/web/tools/chrome-devtools/javascript/
如需转载,烦请注明出处:https://www.fedev.cn/tools/chrome-devtools-javascript.htmljordans for sale sneakers