代码调试系列之前端代码调试的几种基本方法

github文章地址:https://github.com/yaodebian/blog/issues/2

知乎文章地址:https://zhuanlan.zhihu.com/p/56231646

针对前端代码的调试,我们更多的是对javascript代码的调试,我们常用的可能就是向alert、console等方式,同样的对于DOM元素变化的js脚本也可以进行监听调试,然后就是简单的HTML元素的css样式的调试。

接下来我们将一一举栗一些调试方法。

一.alert弹框调试

正对js代码的调试,我们往往需要获取某些变量的值,于是在早期我们往往通过alert方法将变量的值通过弹窗的形式进行打印。

二.console

alert方法对于我们来说或许仍然比较繁琐:每次alert某条信息都需要弹窗,弹窗都会使得我们对页面中的其他区域的操作无效化。
那么,为了能够更方便地调试,各浏览器厂商在相应浏览器中都添加了成为“控制台”的功能,以下以Chrome中开发者工具中的“控制台”为栗。
在我们页面的js代码中,我们可以插入如“console.log(variable 变量)”格式的语句来在浏览器“控制台”中显示变量的值,如:

  • js中有如下语句:
var a = 123
console.log(a)
  • chrome浏览器中通过F12来打开开发者工具,并切换到console选项卡,我们将看到123的a变量的输出结果。

其实,我们也可以直接在浏览器控制台中输入上面的语句,如图:(仍然以上面的栗子为栗)


上面我们通过“console.log”输出了a的值,那如果我们输出的是一个对象,输出的形式是怎样的呢?比如声明一个对象b:

{
  name: 'yaode',
  age: 20
}

通过console.log,我们打印出如下:


其实除了log函数,chrome还给console添加了table函数,如下:

所以,我们可能会想console这个对象可能有很多比较有意思的api等待我们去探索,我们可以通过查看相应的文档来理解:

https://developer.mozilla.org/en-US/docs/Web/API/Console

另外,我们注意到,我们通过在控制台中输入console.log其实就是在控制台中输入js脚本,也就是说可以通过控制台来编写我们的测试代码,


既然控制台中是可以进行js脚本编程的,那么其全局环境是否也是和普通js文件一样是window呢,我们可以简单测试一下:


从上面可以看出,的确是和正常的js脚本文件是一样的全局环境。说到这个,我还依稀记得当初有一个面试官问过我这样一个问题,他说,如果我们在浏览器的控制台中声明一个变量arg,那么js脚本中能够访问到这个变量吗?我们可以做以下的测试:

  • 首先我们在普通的js文本中console.log一个变量arg;
  • 接着我们在控制台中声明一个变量arg;
  • 当我们重新刷新页面后,我们会发现浏览器的控制台中报错了,如图所示:


上面这种情况或许有哥们或者妹子会说你的arg那条语句都没有回车执行过,那我索性执行下可好:
结果是当我执行了那条语句之后,我再刷新页面后,控制台中仍然是报错的,和上面的区别是没有我声明arg的那条语句。
我们可以来分析一下上面的情况,浏览器再加载完js脚本文件之后是立刻执行其中的代码的,对于上面的第一种情况,由于我们的语句压根就没有执行,故而报错也是正常的。而另外,对于第二种情况,从报错来看应该也是没有执行的,我的猜想:

  • 当页面刷新后,我声明arg的语句也销毁掉了,之前的声明的变量在内存中被销毁,也就是仅仅执行了js脚本文件并执行;
    那我到底可不可以通过js文本中的代码获取通过控制台声明的变量呢?我想,之前我们获取失败是因为变量确实不存在,我们可不可以声明一个定时器,循环轮询arg的值,如果存在,则将它输出,这样,我们之后在控制台中声明arg变量即可:
  • 我们在js脚本中声明如下计时器:
setInterval(function () {
  // 之所以通过window来调用arg,主要是为了防止浏览器的报错提示而终止程序的执行
  if (window.arg) console.log(arg)
}, 1000)
  • 在控制台中声明arg:

三.JS断点

我们知道,很多编程语言都能够在编译器中设置它的断点,java可以通过eclipse进行设置,c/c++可以通过vs进行设置,进而我们能够进行相应的调试,js也不例外,我们可以通过浏览器提供的开发者工具进行断点设置。
在之前的调试方法中,我们都需要手动通过某些代码的形式查看某些变量的值,而通过设置断点的方式,可以省去这段调试代码,从而直接查看变量的值。

1.source断点
在开发者工具中,有一个sources的选项卡,在里面我们可以找到我们相应的js脚本代码,通过如下的方式,我们可以设置断点并进行调试:

  • 在souce代码中设置代码断点:


可以看到,只要在相应的行号上点击即可。

  • 当我们刷新页面,程序便会在断点处停止:

  • 接下来,我们可以在旁边的watch项中添加某些表达式,以查看相应的值,如图:


watch的作用就是我们可以通过它查看某些表达式或变量的值。

  • 为了查看程序执行的过程,浏览器当然也提供了相应的按钮,如图:


从左到右,各个图标表示的功能分别为:

    • Pause/Resume script execution(F8 或 Ctrl + \):暂停/恢复脚本执行(程序执行到下一断点停止);
    • Step over next function call(F10 或 Ctrl + '):执行到下一步的函数调用(跳到下一行);
    • Step into next function call(F11 或 Ctrl + ;):进入当前函数;
    • Step out of current function(shift + F11 或 Ctrl + shift + ;):跳出当前执行函数;
    • Step(F9):跳到下一条执行语句;
    • Deactive/Active all breakpoints: 关闭/开启所有断点(不会取消);
    • Pause on exceptions: 异常情况自动断点设置,浏览器会在程序发生异常的那一行设置断点,即当程序会在异常发生处暂停;

2.debugger断点(索性这么叫吧)
这种方法其实和上面的souce断点很像,区别就是这种方法通过在代码中添加debugger来给代码设置断点,当代码执行到该语句的时候就会自动断点。接下去的操作就跟在Sources面板添加断点调试几乎一模一样,唯一的区别在于调试完后需要删除该语句。
既然基本和souce断点的方式一样,那为什么还会有debugger这种方式呢?网上有人给出的解释是:
我们在开发中偶尔会遇到异步加载html片段(包含内嵌JS代码)的情况,而这部分JS代码在Sources树种无法找到,因此无法直接在开发工具中直接添加断点,那么如果想给异步加载的脚本添加断点,此时”debugger;”就发挥作用了。

3.DOM断点
DOM断点,顾名思义就是在DOM节点上添加断点,以监听DOM元素的变化,进而定位到特定的js脚本代码。

  • 当节点内部子节点变化时断点(break on subtree modifications)
    在前端开发越来越复杂的今天,前端JS代码越来越多,逻辑越来越复杂,一个看似简单的Web页面,通常伴随着大段大段的JS代码,涉及诸多DOM节 点增、删、改的操作。难免遇到直接通过JS代码很难定位代码段的情况,而我们却可以通过开发者工具的Elements面板,快速定位到相关DOM节点,这 时候通过DOM断点定位脚本就显得尤其重要了。具体我们还是通过gif演示来看一下吧:


上图演示了对ul子节点(li)的增加、删除以及交换顺序操作触发断点的效果。但需要注意的是,对子节点进行属性修改和内容修改并不会触发断点。

  • 当节点属性发生变化时断点(Break on attributes modifications)
    另一方面,由于前端处理的业务逻辑越来越复杂,对一些数据的存储依赖越来越强烈,而将临时数据存储于DOM节点的(自定义)属性中,是很多情况下开发者优先选择的方式。特别是在html5标准增强自定义属性支持(例:dataset、data-*之类)之后,属性设置应用越来越多,因此Chrome开发者工具也提供了属性变化断点支持,其效果大致如下:


此方式同样需要注意,对子节点的属性进行任何操作也不会触发节点本身的断点。

  • 当节点被移除时断点(Break on node removal)
    这个DOM断点设置很简单,触发方式很明确——当节点被删除时。所以通常情况应该是在执行”parentNode.removeChild(childNode)”语句的时候使用此方式。此方式使用不多。

4.XHR Breakpoints
这几年前端开发发生了翻天覆地的变化,从当初的名不见经传到如今的盛极一时,ajax驱动Web富应用,移动WebApp单页应用风生水起。这一切都离不开XMLHttpRequest对象,而“XHR Breakpoints”正是专为异步而生的断点调试功能。

我们可以通过“XHR Breakpoints”右侧的“+”号为异步断点添加断点条件,当异步请求触发时的URL满足此条件,JS逻辑则会自动产生断点。演示动画中并没有演示到断点位置,这是因为,演示使用的是jquery封装好的ajax方法,代码已经过压缩,看不到什么效果,而事实上XHR断点的产生位置是”xhr.send()”语句。

XHR断点的强大之处是可以自定义断点规则,这就意味着我们可以针对某一批、某一个,乃至所有异步请求进行断点设置,非常强大。但是,似乎这个功能 在日常开发中用得并不多。

5.Event Listener Breakpoints
事件监听器断点,即根据事件名称进行断点设置。当事件被触发时,断点到事件绑定的位置。事件监听器断点,列出了所有页面及脚本事件,包括:鼠标、键盘、动画、定时器、XHR等等。极大的降低了事件方面业务逻辑的调试难度。


演示实例演示了当click事件被触发时和当setTimeout被设置时的断点效果。实例显示,当选中click事件断点之后,两个按钮的被点击时都触发了断点,而当setTimeout被设置时,“Set Timer”断点被触发。

上面是总结的几种js代码调试方法,那么我们通过这些调试方法找到相应的bug后,我们需要修改代码,由于修改源码太麻烦,我们可以直接在souces中的代码中进行修改然后保存(关于source中编辑代码其实也是很讲究的,可以研究一下),再看看运行的效果,可以的话我们再将修改后的代码粘贴到源码中即可。

最后针对DOM的css样式的调试,我们可以通过以下两种方式来查看样式:

发布了80 篇原创文章 · 获赞 91 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/YaoDeBiAn/article/details/86761412
今日推荐