作为一名前端开发者,当代码出现问题时你是怎么去排查的呢?相信大部分童鞋是通过 alert 和 console.log 来解决的。通过这种方式能够解决我们平时遇到的大部分问题,但当我们遇到更为复杂的问题时,上述的方式并不能帮助我们高效地解决问题,这时我们可以通过 Chrome 开发者工具的断点调试功能来帮助我们更高效地排查和解决问题。
一般来说,打开 Chrome 开发者工具有以下三种方法:
- 在Chrome菜单中选择 更多工具 > 开发者工具
- 在页面元素上右键点击,选择 “检查”
- 使用 快捷键 Ctrl+Shift+I (Windows) 或 Cmd+Opt+I (Mac)
Chrome 开发者工具提供了各种方便开发者调试的功能,主要有
代码行断点、DOM 断点、XHR 断点、事件监听器断点、异常断点和功能断点。本章主要讲的是最经常用到的也是最方便调试的代码行断点。
在进行代码行断点调试时,Chrome 开发者工具中的 Sources 面板是我们主要操作的功能区域,我们可以在该面板中对已请求资源进行观察调试。
Source 面板主要分为内容源区(左)、显示区(中)、调试功能区(右)三个区域。
内容源区,分为 Sources、Content scripts 和 Snippets 三个标签 。其中Sources 是指页面中请求的各种资源,它是按照域来划分各种不同的请求资源的(如果你有使用抓包工具 Charles 的经验,那么你会发现这里跟 Charles 中的 Structure 模式是类似的);Content scripts 是指谷歌的扩展程序;而 Snippets 是指创建的小脚本,我们可以在该标签内创建我们自己的脚本并执行它。这里我们只需要关心 Sources 即可。
显示区,显示所选择的资源内容,在进行代码行断点调试中,我们需要在该区域设置断点,并且在调试过程中,我们可以在该区域获得许多关于变量和函数的信息。
调试功能区,在该区域我们根据不同的调试需求进行不同的操作,如执行下一步代码、激活和禁用断点等,在断点调试中观察程序在执行中的执行上下文栈(Call Stack)、作用域链(Scope),以及设置其它各种不同类型的断点等等。
接下来对调试功能区进行详细的介绍,调试功能区如下图所示:
我们可以看到调试功能区上方有各个不同的按钮,当鼠标移至该按钮上方时会出现对该按钮功能的简短介绍,从左至右如下:
- Pause/Resume script execution :暂停/恢复脚本执行。
- Step over next function call :跳过下一个函数上下文。即不遇到函数时,执行下一步;遇到函数时,不进入函数直接执行下一步。
- Step into next function call :跳进下一个函数上下文。即不遇到函数时,执行下一步;遇到函数时,进入函数上下文。
- Step out of current function :跳出当前函数。
Deactivate/Activate breakpoints :停用/激活全部断点。 - Pause on exceptions/Don't pause on exceptions :暂停捕获异常/不暂停捕获异常。
下方则是一些不同的断点调试模式或者是调试过程中一些信息的观察等:
- Watch :观测表达式。为目前断点添加表达式,使得每次断点往下走一步都会执行你的代码。
- Call Stack :执行上下文栈。执行上下文栈是指一个存放各个执行上下文的栈(一种先进后出的数据结构)。
- Scope :作用域链。每个执行上下文都有其作用域链,作用域链包含了当前执行上下文和上层执行上下文的变量对象。
- Breakpoints :代码行断点。
- XHR Breakpoints :XHR 断点。
- DOM Breakpoints :DOM 断点。
- Global Listeners :全局监听。
- Event Listener Breakpoints :事件监听器断点。
介绍完 Sources 面板后,让我们来看看如何进行代码行断点调试。
其中代码行断点还分为普通代码行断点调试和有条件的代码行断点调试。
断点设置
代码行断点,顾名思义就是在具体的资源文件中的某一行代码设置断点,在前面我说过 Sources 面板主要分为内容源区(左)、显示区(中)、调试功能区(右)三个部分,当我们在内容源区选择了包含有 js 代码的资源后,显示区则会显示相应的源代码,只要在显示区中显示代码行数的地方「左键」或者「右键 - Add breakpoint」即可设置普通代码行断点。
如果在显示区中显示代码行数的地方「右键 - Add conditional breakpoint」,则会在代码行下方出现一个输入条件表达式的框,输入触发断点的条件后按下 Enter,即可设置有条件的代码行断点。之后只有在触发了条件表达式的情况下才会触发该断点。
设置后在调试功能区的 Breakpoints 则会显示出我们当前设置的断点,在这里能够激活禁用或删除断点。
观察信息
设置了代码行断点后刷新页面,程序会在执行这行代码之前暂停,这时我们可以在显示区观察到当前环境的各个变量和函数信息,也能够在调试功能区观察当前环境的各种信息,如执行上下文栈、作用域链等。
上图中的代码是一个闭包的例子,可以看到函数 innerFn 的作用域链包含了自己执行上下文的变量对象、函数 outerFn 上下文的变量对下和全局对象,如下所示
innerFnContext={
scope:[innerFnContext.VO,outerFnContext.VO,globalContext.VO]
}
在大多数情况下,我们会把 innerFn 当作是闭包,而在 Chrome 开发者工具中则会把 outerFn 当作闭包,如图中显示 Closure(outerFn),这一点我也在 《 javascript 闭包详解 》 中有提到过,感兴趣的童鞋可以去看看。
执行下一步代码
最后在调试功能区的的上方按钮部分,我们根据需要点击不同的按钮,执行下一步的操作,观察代码执行情况和变量函数信息等。