提到JS的调试,写过JS的同志都知道:简单,console.log解决一切问题。其实JS调试还有很多好用的工具可供选择,使用起来会比直接log更为高效,但是我在工作中很少见到有同事会使用这些工具,老菠的这个系列就是向大家介绍如何使用这些工具的
认识Chrome JS 调试工具
首先,让我们单击键盘上的F12,选中“Sources”一栏,你应该会看到下面的这个界面:
我们可以把它分成三个部分:文件区域,代码展示/编辑区域,调试功能区域(我自己起的名)。
文件区域用来展示文件,你可以在文件区域通过单击选择文件。
被选中的文件会展示在代码展示/编辑区,在这里可以对选中的文件进行编辑,保存,添加断点等操作。
在调试功能区,我们可以对代码进行调试,查看程序运行的情况。
下面让我们分别详述这几个区域。
1. 文件区域
这是一个文件选择面板,就跟vscode左边的文件栏一样,它又分为几个子栏目:
1.1 Page栏
这一栏想必大家都见过,展示当前网页上的所有文档,基本上就是页面所使用的JS,HTML,CSS,图片这些文件(如下图)
1.2 Filesystem栏
这一栏允许我们选择本地文件:
这个功能使得chrome可以作为一个IDE使用(可能没人会这么用哈),你可以加载本地项目,在编辑区修改,保存
1.3 Overrides栏
这一栏的作用是,可以用本地文件覆盖Page里面的文件。它的用法是,在本地创建一个和Page栏结构完全相同的目录结构,例如,打开百度首页,来到Page一栏,可以看到一个形如top -> www.baidu.com -> index的目录结构
然后我在本地也创建一个同样结构的目录,index.html里的内容是一行文本“hello world”:
然后回到百度,进入Overrides一栏,选择刚才创建好的目录,然后刷新页面,发现页面已经被替换成我的index.html,当然JS文件也可以如此操作。被覆盖的文件上可以看到一个紫色小圆点,说明该文件被本地文件替换
1.4 Content scripts栏
插件的content scripts
1.5 Snippets栏
这个是一个非常实用的功能,允许我们创建代码片段,直接在chrome里运行。
如果你是个web开发者,大概有过这样的经历:想运行一段js代码做实验,怎么办呢?随便找个网页,F12,到console里敲入代码,直接运行。因为浏览器是我们最容易获取的JS运行环境,所以这么做可以让我们快速完成JS小实验。但在console窗口写代码不是很舒服,换行、缩进都很麻烦,调试起来也很烦。这时候可以用Snippets,在这里你可以很舒适地编辑代码,并运行
后面我将借助一段snippet来介绍调试工具的使用
2. 代码展示/编辑区域
这个区域允许我们
- 查看、编辑代码,或浏览其他资源文件
- 在调试过程中添加断点,查看变量的值等
3. 调试功能区域
上文提到,在“代码展示/编辑区域”可以设置断点,当程序运行至断点处,就会暂停运行,这是断点调试的基础逻辑。
我们用下面这段代码为例
function getSum(a, b){
const op1 = Number(a);
const op2 = Number(b);
const sum = op1 + op2;
if(isNaN(sum)){
throw new Error("One of the operation number can't be converted to a number");
}
return sum;
}
function printSum(a, b){
console.log(getSum(a, b));
}
printSum(6, 6);
如果我在第5行打上断点,然后运行程序,那么当程序运行到这一行的时候就会停止:
如上图所示,当程序在断点处停止时,调试工具允许我们做很多事:
- 我们可以在“代码展示/编辑区域”查看所有变量的值
- 在Watch里也可以访问所有处于该scope的变量,也可以在这里对任意表达式求值
- 查看程序中的线程(Threads),以及线程所处的状态
- 查看程序运行的调用栈(Call Stack),可以选择转移至调用栈的任意一层
- 查看当前所处的作用域(Scope)
我们也可以选择让程序继续运行来进行调试,Chrome提供了多种方法:
3.1 断点调试工具栏
这里以下面这段代码为例,来解释断点调试工具是如何使用的
function getSum(a, b){
const op1 = Number(a);
const op2 = Number(b);
const sum = op1 + op2; // 断点B
if(isNaN(sum)){
throw new Error("One of the operation number can't be converted to a number");
}
return sum;
}
function printSum(a, b){
const sum = getSum(a, b) // 断点A
console.log(sum);
}
printSum(6, 6);
-
继续(Resume)按钮,让程序继续运行,直到遇到下一个断点。
当程序停在断点A时,点击继续,程序会运行到断点B,然后停住。再次点击继续,程序会运行至结束。
-
跨过(step over next function call)按钮:让程序前进一行。
它的作用是运行下一行代码,然后停住,如果下一行代码里有函数调用,Chrome是不会进入该函数的,而是直接将该函数跑完。当程序停在断点A时,点击跨过,程序会进入函数getSum,停在函数getSum的第一行。了解“调用过程”的同志可以这么理解,这个操作前后,调用栈的内容是不变的。
-
跨入(step into next function call)按钮:它的作用同样是运行下一行代码,然后停住。
不同点在于,如果下一行代码里有函数调用,Chrome会进入该函数。调用栈里会增加一个函数。
-
跨出(step out of current function call)按钮:它的作用是运行当前函数其余的代码,并从函数中出来,然后停住。
当程序通过了断点A,停在断点B时,点击跨出,函数getSum的余下代码会运行完,最后停在函数printSum的第二行
-
下一步(step)按钮:执行下一条指令?
说实话,老菠没发现这个按钮跟“跨入”按钮功能上有什么区别,有知道的老铁还请不吝赐教。
-
断点开关(Deactivate/Activate breakpoints)按钮:它可以使所有断点失效或生效。
当处于失效档位时,调试器中的所有断点都不会起作用,程序不会再断点处中断
-
异常中断开关(Pause on exceptions):处于激活状态时,一旦发生异常,程序就会在异常发生处中断
小结
这一篇,老菠介绍了chrome的sources面板,和断点调试的一些基础概念。希望对你有所帮助