前言

前端开发中我们最常需要调试的部分是 JS ,在调试 JS 的过程中,我们最常使用的方法便是 debug 调试。何为 debug 调试? debug调试又名断点调试,它指的是在程序指定位置设置断点,当程序运行到这个断点时会暂停执行并保留当前状态,我们可以通过查看暂停时的程序状态来定位和排查问题。

那么为什么我们需要用这种调试方法呢?实际开发中,当我们完成一个功能,但是发现在浏览器中未否生效时,如果没有很丰富的经验,我们很难直接定位到问题所在。因为这个时候程序已经完成了执行,程序中大部分使用过的变量已经被回收了。但是有了 debug 调试,我们可以在程序运行过程中实时查看它的运行状态,甚至可以一步一步得调试,来看每一个变量在每一步是如何变化的,这对我们排查异常非常有效。接下来我们来看以下几种常用的 debug 调试方法。

1. 代码中设置debugger断点或打印信息

最简单的 debug 方法,是在我们希望调试的代码前加上一行

  1. debugger;

只需要这么一行代码,就能使得程序的滚滚推进戛然而止,并且停在你想要的位置。我们亲手尝试一下,先写下一段 HTML

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>debug调试</title>
  5. </head>
  6. <body>
  7. <div>
  8. <p id="word">这是一段文字</p>
  9. </div>
  10. </body>
  11. <script type="text/javascript" src="action.js"></script>
  12. </html>

再在与 HTML 文件的相同位置写下如下 JS ,命名为 action.js

  1. function getNewName(name1,name2){
  2. var c = name1.slice(0,4),
  3. d = name2.slice(4);
  4. return c + d ;
  5. }
  6. function showNewName(){
  7. var a = 'FreeStyle',
  8. b = 'CuteFaller';
  9. var newName = getNewName(a,b);
  10. var word = document.getElementById('word');
  11. setTimeout(function(){
  12. var newWord = '新文字:' + newName ;
  13. word.innerText = newWord ;
  14. word.setAttribute('isNewName',true)
  15. },1000)
  16. }
  17. showNewName();

保存后在浏览器中打开 HTML 文件,我们会发现浏览器中“这是一段文字”在一秒钟之后变成了另一行文字。为什么会有这样的变化呢?我们在程序中设置一个断点来调试看看。在 getNewName 方法中写下一行 debugger;

  1. function getNewName(name1,name2){
  2. debugger;
  3. var c = name1.slice(0,4),
  4. d = name2.slice(4);
  5. return c + d ;
  6. }

保存文件并刷新浏览器,我们发现页面进入了断点位置

debug断点调试 - 图1进入断点

打开控制台,此时我们停留在 Sources 一栏,还记得上一章介绍的内容吗? Sources 展示着当前页面的资源,因此我们所写的 JS 代码自然也是可以在这里找到的。

仔细观察断点处,我们看到给 getNewName 方法传递的两个参数都有了值,控制台在代码边上备注了 “name1 = “FreeStyle” , name2 = “CuteFaller””这是当前函数执行时的变量值。

当我们用鼠标选中 name1.slice(0,4) 这一行,我们可以看到鼠标上方出现了一个显示 “Free”的气泡,这是浏览器执行这一句指令返回的结果。
debug断点调试 - 图2查看运行情况

断点状态下按 F8 可以跳过当前断点继续执行,直到程序结束或是进入到下一个断点。按 F10 可以进行单步调试,即一行一行得执行代码,每一行的细节都可以进行查看。

除了可以在代码中写 debugger; 我们还可以通过 console.log(); 方法打印我们想要的信息。

  1. function getNewName(name1,name2){
  2. var c = name1.slice(0,4),
  3. d = name2.slice(4);
  4. console.log(c);
  5. return c + d ;
  6. }

在代码中加上一行打印,刷新页面发现没有进入断点。打开控制台,我们在 Console 中看到一行打印信息 “Free” 这就是我们打印的变量 c 的值。程序在执行到打印 c 的时候会将 c 当时的值打印到控制台,这样我们不需要进入断点也能够查看自己想知道的变量在运行阶段的值。

当然,我们还可以将两者并存,当程序进入到断点的时候,我们能通过 Console 控制台查看变量的值。断点状态下, Console 控制台会保留运行时的值和状态,我们可以在控制台直接访问当前执行函数内的变量。此外,当程序报错时,我们会第一时间在 Console 中看到,点击 Console 中的错误详情,就会跳转到 Sources 中的报错文件里,因此某种程度上,在调试过程中两者有着非常密切的联系。

最后要着重提醒的一点是,由于 debugger 和 console 这两种方式都是在源代码上添加的调试指令,所以当我们完成调试以后,一定要将它们删除,否则代码上线后他人也会进入到断点中,无法流畅得使用网页。

2. 浏览器 Sources 中手动打断点

上一节内容我们介绍了如何进行 debug 调试,大家可能会觉得这样调试有些繁琐,要去源码中加调试代码,调完还得记得删除掉。那么我们在这一章,给大家提供一个简单明了的办法 —— 直接在 Sources中调试。

大家可以回顾一下上一章中我们对 JS 的调试,在 Sources 中通过 ctrl + P 找到我们希望调试的代码文件,ctrl + F 定位到我们想要调试的行。接下来,我们可以在文件的侧边栏上设置断点,设置方法就是在行数上单击。单击后行数上出现一个蓝色的便签,就表示已经在这一行上设置了断点,接下来刷新页面就可以进入到断点中查看了。

进入断点之后我们其实可以在浏览器的文件上进行编辑,不用进入源文件修改代码,就能够进行代码尝试。
debug断点调试 - 图3编写临时代码

比如我们先进入到函数 getNewName 的断点中,再将代码 d = name2.slice(4); 改写为 d = name2.slice(4,6); 按 ctrl + S 保存。接下来按 F10 单步执行,当执行到这一句时,我们发现浏览器已经按照我们改写的代码执行了 d = “Fa”,说明我们的临时代码生效了。

debug断点调试 - 图4临时代码生效

跳过断点,页面上显示出 “新文字:FreeFa”,说明我们的改动并不影响后续逻辑的继续执行。但是数据已经按我们期望的临时改动展现了出来。

debug断点调试 - 图5继续执行

这样进行代码调试我们不需要改变源代码即可对问题进行排查,非常灵活和快捷。想在什么地方设置断点只需要在 Sources 中找到对应的文件,点击一下想设置断点的那一行即可,无需改动源码,效率大大提升。调试结束后再次点击这些断点即可解除断点,对他人的网页不会造成任何影响。

3. 浏览器 DOM 节点设置断点

最后我们再来看看 DOM 节点上设置断点的方法。我们在开发页面的时候,往往会对 DOM 节点做变更处理,假设业务场景比较复杂,你并不能确定某一个 DOM 的变化是由哪一个文件执行导致的。这时我们可以换一个角度,从 DOM 出发,监听 DOM 变化,再反过来追查引发其变化的代码。

浏览器提供了这样的操作,我们先在 Elements 模块中找到我们需要监听的 DOM 节点(这里我们以 p 节点为例),找到以后点击右键,选择 Break On 。里面可以监听三种变化类型:subtree modifications、attribute modifications和node removal。分别是对应子节点树更新、修改节点属性和移除节点。

debug断点调试 - 图6监听节点操作

这里我们选择 attribute modifications 。接下来我们刷新页面,一秒钟之后进入断点。查看断点的位置,这里的代码是

  1. word.setAttribute('isNewName',true)

正是这行代码在给 p 标签添加了名为 isNewName 的属性。

debug断点调试 - 图7DOM 变化进入断点

这样我们就定位了引起 p 节点属性变化的 JS 代码,是不是很方便?对于不符合预期的节点变换,也可以通过这样的方式去追踪,真相很快就能浮出水面啦。

总结

以上,是我们常用的几种 debug 调试方法。开发过程中妥善利用它,对我们的开发效率和排查问题的能力都有很大的帮助。当然,想学会调试最重要的还是要多尝试,熟能生巧。利器已在眼前,还请亲手体验。