更加快速地调试JavaScript
熟悉了解工具对于完成任务来说有着重要的作用。尽管JavaScrip是t出了名的难调试,但如果你知道一些窍门,那你可以花更少的时间去解决这些error和bug。
我们在这里列举了16个你可能不知道的调试技巧,但它们可能是你想要在下次调试JavaScript代码之前记住的。
如果你想更快地调试JavaScript的bug,你可以尝试Raygun崩溃报告( Raygun Crash Reporting ),它可以提供给你关于bugs的告警以及堆栈追踪(stack trace)。
虽然许多技巧也同样适用于其他的检查器(inspector),但这里提及的大部分的技巧是基于Chrome和Firefox的。
1. debugger
除了console.log,debugger是我最喜欢的快速直接的调试工具。如果你在代码中嵌入debugger;,Chrome执行到这里时会自动停止。你甚至可以把它放在条件语句中,这样它只有在你需要的时候才会运行。
- if (thisThing) {
- debugger;
- }
- if (thisThing) {
- debugger;
- }
2. 在表格中显示对象
有时候你想看一组特别复杂的对象。你可以用console.log来打印出整个列表,也可以使用console.table来帮助显示。这样可以使你更简单明了地看到你所处理的对象。
- var animals = [
- { animal: 'Horse', name: 'Henry', age: 43 },
- { animal: 'Dog', name: 'Fred', age: 13 },
- { animal: 'Cat', name: 'Frodo', age: 18 }
- ];
- console.table(animals);
它将会输出:
3. 尝试所有的尺寸
尽管在你的桌上拥有每一种移动设备特别棒,但这并不现实。不如重新调整视觉视口(viewport)的大小?Chrome提供了你所需要的一切。打开浏览器的inspector并点击选中设备模式(device mode)的按钮。你就可以观察到媒体查询(media queries)了。
4. 如何快速找到你需要的DOM元素
在元素面板中标记一个DOM元素,并在控制台中使用它。Chrome的Inspector会保存历史记录中最近的5个元素,最后被标记的元素会被显示成 1,以此类推。如果你按顺序标记“item4“,”item-3“,”item-2“,”item-1“,”item-0“,那么你可以像下图这样在控制台中访问DOM节点。
5. 用console.time()和console.timeEnd()来衡量loops快慢
知道一段代码到底需要多长时间来执行是很有帮助的,尤其是当你在调试执行速度慢的代码的时候。你甚至可以通过给函数赋上不同的标签值来设置多个timer。让我们看看它是怎么工作的:
- console.time('Timer1');
- var items = [];
- for (var i = 0; i < 100000; i++) {
- items.push({index: i});
- }
- console.timeEnd('Timer1');
它将会输出:
6. 得到函数的堆栈追踪
你可能知道JavaScript框架可以快速产生很多代码。
你会有许多的视图,并且触发很多事件,所以你终究会遇到一个情况,会想知道是什么触发了一个特定的函数调用。因为JavaScript不是一个非常具有结构性的语言,所以有时候你很难知道发生了什么事,什么时候发生了这件事。这就是使用console.trace(或者直接在控制台中使用trace)的时候了。试想一下你想查看在第33行car实例中关于funcZ的函数调用的整个堆栈追踪:
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
第33行会输出:
现在我们可以发现func1调用了func2,func2调用了func4,而func4创建了一个Car的实例并调用了car.FuncX,以此类推。尽管你认为自己已经对脚本特别熟悉,你仍然会发现这个方法特别得方便。如果你想提高你的代码质量,你可以获取所有的追踪和相关的函数。它们中的每个都是可点击的,你可以来回切换,对你来说就像一个菜单一样。
7. 解压缩代码使得调试JavaScript更加简单
有时候你可能会在线上的产品中遇到这样的问题,服务器并不能提供源代码映射(souce maps)的功能。不用怕,Chrome可以将你的JavaScript文件解压缩成更加易读的形式。这些代码不会和真的代码一样有帮助,但是至少你能明白发生了什么。你可以点击在inspector中源代码视图下方的 {}
按钮来格式化代码。
8. 快速找到需要被调试的函数
如果你想要在一个函数中设置一个断点,有两种方法:
- 在inspector中找到那行,添加一个断点
- 在脚本代码中添加debugger
上述的两种方法,你都需要自己手动在文件中找出你需要调试的特定的那一行代码。一个比较不为人知的办法是,在控制台中使用debug(函数名),这样脚本会在执行到这个函数时自动停下。
这个方法特别快,但缺点是它没法使用在私有函数和匿名函数上。除此之外,这大概是最快找到需要调试函数的方法了。(注意:有一个函数叫做console.debug,尽管名字相似,但和这个并不是一回事)
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
- var car;
- var func1 = function() {
- func2();
- }
- var func2 = function() {
- func4();
- }
- var func3 = function() {
- }
- var func4 = function() {
- car = new Car();
- car.funcX();
- }
- var Car = function() {
- this.brand = ‘volvo’;
- this.color = ‘red’;
- this.funcX = function() {
- this.funcY();
- }
- this.funcY = function() {
- this.funcZ();
- }
- this.funcZ = function() {
- console.trace(‘trace car’)
- }
- }
- func1();
在控制台中输入debug(car.funcY),脚本会在有函数调用car.funcY时停下并进入调试模式。
9. 排除与bug无关的脚本
如今我们在web应用中会用到许多的库和框架,它们中的大部分是经过完整的测试并且相对而言可以被假设成是没有bug的。但是debugger还是会步入所有这些与调试任务没有关系的文件。解决的方法是把你不需要调试的脚本放进黑盒里,这里头也可以包括一些你自己写的脚本代码。你可以在这篇调试黑盒的 文章 中阅读到更多的细节。
https://raygun.com/blog/javascript-debugging-with-black-box/
10. 在复杂的调试中找到重要的事情
在更多复杂的调试情境中,我们有时会想要输出许多行。在这里,我们可以利用各种console函数来使输出使输出的内容保持一个更易读的结构。比如,console.log,console.debug,console.warn,console.info,console.error等等。你可以在inspector中筛选它们。有时候这可能不是你在调试时想要达到的效果,但如果需要,你可以使你输出的信息更加多样性并有自己的风格。当你想调试JavaScript时,你可以使用CSS来创建你自己的格式化控制台信息:
- console.todo = function(msg) {
- console.log(‘ % c % s % s % s‘, ‘color: yellow; background - color: black;’, ‘–‘, msg, ‘–‘);
- }
- console.important = function(msg) {
- console.log(‘ % c % s % s % s’, ‘color: brown; font - weight: bold; text - decoration: underline;’, ‘–‘, msg, ‘–‘);
- }
- console.todo(“This is something that’ s need to be fixed”);
- console.important(‘This is an important message’);
它将会输出:
在console.log()中,你可以使用%s来代表string,%i来代表integers,%c来代表自定义风格。你可能可以找到其他更好的方法来使用这些风格。如果你使用单页应用框架(single page framework),你或许想要message对应一种风格,model对应一种风格,collections对应一种风格,而controller对应另一种风格,等等。
11. 查看特定的函数调用和参数
在Chrome的控制台中,你可以查看一些特定的函数。每次这些函数被调用时,传入函数的参数就会被输出。
- var func1 = function(x, y, z) {
- //....
- };
它会输出:
这是一个查看传入函数参数的好办法。最理想的情况下,控制台可以辨别出函数需要多少个参数,但实际上并不能。在上述的例子中,func1需要三个参数,但只传入了两个。如果在代码中没有做好处理,这样会导致潜在的bug。
12. 快速在控制台中访问元素
一个在控制台中更快地完成选择器查询(querySelector)的方法是使用. ('css-selector')会返回第一个匹配,.$$('css-selector')会返回所有的匹配。如果你使用一个元素多于一次,那么可以把它存为一个变量。
13. Postman是非常好的工具
许多开发者使用Postman去配合Ajax请求的使用。Postman特别得棒,但令人烦恼的是,每打开一个新的浏览器窗口,就需要写一个新的请求对象,然后再测试它。
有时候用浏览器更加简单。当你这么做时,如果是一个密码安全页面(password-secure page),你不再需要为认证cookie担心。
在Firefox编辑和重新发送请求,你只需要打开Insepctor,到Network标签页下,右键点击你想要修改的请求然后编辑,再重新发送。
现在你可以更改任何你想要的东西,更改header,编辑参数,然后点击重新发送。
下面我展示了一个有着两种不同属性的请求:
14. 在节点上设置断点
DOM可以是一件特别有趣的事情。有时候有些东西改变了,你却不知道为什么。然而,当你需要调试JavaScript时,你可以通过Chrome使一个DOM元素停止改变。你甚至可以看见它的属性。在Chrome的Inspector中,右键点击那个元素并选择一个设置断点的条件:
15. 使用页面提速服务(page speed service)
有许多服务和工具可以帮助你审查页面的JavaScript,找出那些运行缓慢和有问题的地方。其中的一个工具是 Raygun Real User Monitoring 。除了帮助找到JavaScript问题(如外部脚本加载缓慢,不必要的CSS,过大的图片),这个工具还在其他方面也十分有帮助。它还可以帮你找到一些无意间导致加载时间过长,或者脚本无法正常执行的JavaScript问题。
你还可以用它来测量JavaScript代码的性能提高,并跟踪变化。
16. 多使用断点
最后,合理正确地使用断点可以帮助你成功调试。尝试在不同的场景下用不同的方式使用断点。
你可以点击元素来设置断点,从而那个元素被修改时执行会停止。你也可以在开发者工具的Debugger或者Sources标签页(取决于你的浏览器)中,为任何源代码设置XHR断点来停止Ajax请求。在同样的地方,当异常抛出时代码的执行也会被暂停。你可以在浏览器中使用各种断点来最大化你找到bug的几率,而不是把时间花在寻找外部的工具上。
总结
综上所述,有许多方法可以帮助调试JavaScript代码。我们在这儿已经列举了其中的16个。如果你想开始找一些依靠浏览器之外的工具帮助优化浏览器,这儿还有一篇特别有帮助的 文章 列举了一些JavaScript的调试工具。无论怎样,你应该能够利用这些调试技巧开始调试你的JavaScript代码了,使你的代码没有bug,并为部署和发布做好准备!