是怎么调试 JavaScript 程序的?最原始的方法是用 alert() 在页面上打印内容,稍微改进一点的方法是用 console.log() 在 JavaScript 控制台上输出内容。嗯~,用这两种土办法确实解决了很多小型 JavaScript 脚本的调试问题。不过放着 Chrome 中功能越发强大的开发者工具不用实在太可惜了。本文主要介绍其中的 JavaScript
断点设置
和
调试
功能,也就是其中的 Sources Panel(以前叫 Scripts)。如果你精通 Eclipse 中的各种 Java 调试技巧,那么这里的概念都是类似。写作本文时使用的 Chrome 版本为 25.0.1364.172。
最上面是 f(),然后是 g()。调用栈中的每一层叫做一个 frame,点击每个 frame 可以跳到该 frame 的调用点上。
Call Stack 列表的下方是 Scope Variables 列表,在这里可以查看此时局部变量和全局变量的值。
在断点调试时,可以用鼠标选择想要查看的变量或表达式,然后右键菜单执行“Evaluate in Console”,就可以看到该表达式的当前的值了。
上面 try 里面的代码会遇到异常,但是后面的 catch 代码能够捕获该异常。如果是所有异常都中断,那么代码执行到会产生异常的 throw 语句时就会自动中断;而如果是仅遇到未捕获异常才中断,那么这里就不会中断。一般我们会更关心遇到未捕获异常的情况。
在 DOM 元素上设置断点
如图所见,在元素审查的 Elements Panel 中在某个元素上右键菜单里可以设置三种不同情况的断点:
所有开发工具中的快捷键都可以在界面右下角的设置中查到。断点调试时一般用的是 F8、F10、F11或 Shitf+F11,但在 Mac OS 上 F10 等功能键可能与系统默认的快捷键冲突。没关系,它们分别可以用 Cmd+/ 、Cmd+'、Cmd+; 、Shift+Cmd+; 代替。
按钮用于把杂乱的代码重新格式化为漂亮的代码,比如一些已被压缩的 js 文件基本没法看、更没法调试。点一下格式化,再点一下就取消格式化。
美化前
美化后
基本环境
Sources Panel 的左边是内容源,包括页面中的各种资源。其中,又分 Sources 和 Content scripts。Sources 就是页面本身包含的各种资源,它是按照页面中出现的域来组织的,这是我们要关注的。异步加载的 js 文件,在加载后也会出现在这里的。Content scripts 是 Chrome 的一种扩展程序,它是按照扩展的ID来组织的,这类扩展实际也是嵌入在页面中的资源,它们也可以读写DOM。编写、调试这类扩展的开发者才要关心它们,如果你的浏览器没安装任何扩展,那么
Content scripts 就看不到任何东西。
Sources Panel 的中间主区域用于展示左边资源文件的内容。
Sources Panel 的右边是调试功能区,最上面的一排按钮分别是暂停/继续、单步执行、单步跳入、单步跳出、禁用/启用所有断点。下面是各种具体的功能区。稍后介绍。
注意,左右两边的区域默认可能收缩在两侧没有显示出来,点击两侧的伸缩按钮
展示出来。左边区域展示出来时默认是自动收缩状态,点击旁边的 pin 按钮
就不会缩回去了。
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/9xmVMJ5kZ_05sUW6CYfKSg==/2488801744093571844.png)
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/n8FszOIDqqeTLZZc0RyzDg==/6597833927238692676.png)
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/Dah0EclEehzXDLLX5LgEYw==/6597175319774710380.png)
最下面还有一些功能按钮很有用。
在源代码上设置断点
通过左边的内容源,打开对应的 JavaScript 文件,鼠标点击文件的行号就可以设置和删除断点。添加的每个断点都会出现在右侧调试区的 Breakpoints 列表中,点击列表中断点就会定位到内容区的断点上。如果你有多个文件、多个断点的话,利用 Breakpoints 列表中的断点快速定位非常方便。
![Chrome 中的 JavaScript 断点设置和调试 - hanguokai - 韩国恺的博客](http://img1.ph.126.net/0UVZvGApOtzEfGT2OEYERQ==/6597276474842902600.png)
对于每个已添加的断点都有两种状态:激活和禁用。刚添加的断点都是激活状态,禁用状态就是保留断点但临时取消该断点功能。在 Breakpoints 列表中每个断点前面都有一个复选框,取消选中就将禁用该断点。断点位置的右键菜单中也可以禁用断点。也可以在右侧功能区上面
按钮临时禁用所有已添加的断点,再点一下恢复原状态。
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/zNuuk51nRCxcu5M4xg23hA==/6597622821006153054.png)
条件断点:在断点位置的右键菜单中选择“Edit Breakpoint...”可以设置触发断点的条件,就是写一个表达式,表达式为 true 时才触发断点。
查看断点的环境
调用栈(Call Stack):
在断点停下来时,右侧调试区的 Call Stack 会显示当前断点所处的方法调用栈,比如有一个函数 g() 其中又调用了函数 f() ,而我在 f() 中设置了一个断点,那么我在 console 中执行函数 g() 的时候会触发断点,其调用栈显示如下:
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/8at-d-exYYNSf3wdS1KfBA==/6598138491959366940.png)
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img2.ph.126.net/5_Zh6mPy-iSI2Qx3e7OLTA==/6598125297819829076.png)
此外,还可以在 frame 上用右键菜单重新开始执行当前 frame,也就是从该 frame 的开始处执行。比如在函数 f() 的 frame 上 Restart Frame, 断点就会跳到 f() 的开头重新执行,context 中的变量值也会还原。
这样结合变量修改和编辑代码等功能,就可以在当前 frame 中反复进行调试,而不用刷新页面重新触发断点了。
查看变量
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img1.ph.126.net/48sskp-sJLAEviOHN9S8-g==/6597302863121970256.png)
执行选择的代码
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img1.ph.126.net/g6ybRrPRj2D8L_PA0thE0g==/6598080217843094290.png)
中断下次要执行的 JavaScript 语句
右侧调试区的上面的“中断/继续”按钮还有一个功能,
在没有触发断点时,点一下这个按钮就会进入“准备”中断的状态,页面下一次执行 JavaScript 语句时会自动中断,比如触发了一个点击动作时会执行的代码。
临时修改 JavaScript 代码
通常我们在调试代码时习惯:修改代码→刷新页面→重新检查,这么一个循环。但其实 Chrome 中可以临时修改 JS 文件中的内容,保存(Ctrl+S)就可以立即生效,结合 Console 等功能就可以立即重新调试了。但注意这个修改是临时的,刷新页面修改就没了。
异常时断点
在界面下方能看到
按钮,它是设置程序运行时遇到异常时是否中断的开关。点击该按钮会在3种状态间切换:
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/Lc7mnvcr4FwE0HeC4laSbA==/6597601930285221144.png)
默认遇到异常不中断
遇到所有异常都会中断,包括已捕获的情况
仅在出现未捕获的异常时才中断
主要解释一下状态2和状态3的区别
有时候我们需要监听某个 DOM 被修改情况,而不关心是哪行代码做的修改(也可能有多处都会对其做修改)。那么我们可以直接在 DOM 上设置断点。
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/IVpOoHRJ9h4G8gXir-993A==/2502875492929123368.png)
- 子节点修改
- 自身属性修改
- 自身节点被删除
选中之后,Sources Panel 中右侧的 DOM Breakpoints 列表中就会出现该 DOM 断点。一旦执行到要对该 DOM 做相应修改时,代码就会在那里停下来,如下图所示。
会在那里停下来,如下图所示。
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/NgXXLtx4kCvMor64Wr5hCQ==/1023724490314614306.png)
XHR 断点
右侧调试区有一个 XHR Breakpoints,点击+ 并输入 URL 包含的字符串即可监听该 URL 的 Ajax 请求,输入内容就相当于 URL 的过滤器。如果什么都不填,那么就监听所有 XHR 请求。一旦 XHR 调用触发时就会在 request.send() 的地方中断。
按事件类型触发断点
右侧调试区的 Event Listener 列表,这里列出了各种可能的事件
类型。勾选对应的事件类型,当触发了该类型的事件的 JavaScript 代码时就会自动中断。
调试快捷键
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img2.ph.126.net/pKs3MVL1RjfRENbKvDcOYQ==/6597826230657300767.jpg)
//@ sourceURL 给 eval 出来的代码命名
有时候一些非常动态的代码是以字符串的形式通过 eval() 函数在当前 Javascript context 中创建出来,而不是作为一个独立的 js 文件加载的。这样你在左边的内容区就找不到这个文件,因此很难调试。其实我们只要在 eval 创建的代码末尾添加一行 “
//@ sourceURL=name“
就可以给这段代码命名(浏览器会特殊对待这种特殊形式的注释),这样它就会出现在左侧的内容区了,就好像你加载了一个指定名字的 js 文件一样,可以设置断点和调试了。下图中,我们通过 eval 执行了一段代码,并利用 sourceURL 将它命名为 dynamicScript.js ,执行后左侧内容区就出现了这个“文件”,而它的内容就是 eval 的中的内容。
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/LMfR9cctSwFeT-LB8jKzWg==/6597570044448017583.png)
实际上,//@ sourceURL 不仅仅可以用在 eval 的代码中,任何 js 文件、甚至是 Javascript Console 输入的代码都可以用,效果一样!
格式化代码(Pretty Print)
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img1.ph.126.net/xzuTrMCRsC-XF6u_EcB1eQ==/2518638091625050894.png)
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img1.ph.126.net/wEea1CX_LP8NMKHYPrsGOw==/6597894400378218400.png)
![Chrome 断点设置 - hanguokai - 韩国恺的博客](http://img0.ph.126.net/kkD-kf5OA0XItqMUIr_1NQ==/994451092736837238.png)
参考资料: