JavaScript调试专家指南:帮你更好、更快地调试代码

2019 年 7 月 02 日

JavaScript调试专家指南:帮你更好、更快地调试代码

你是那种在代码出问题时习惯性打开控制台开始调试的开发者吗?如果是的话就看完本文吧。


这篇文章会向你介绍 Chrome 开发工具中的一些非常有用的工具和技巧,能帮你更好、更快地调试 Javascript 代码


切入主题前先送你一个小提示:使用Bit可以轻松管理、共享并复用你的 JS 组件。想要做出更优秀、更可持续的代码,模块化和可复用性是非常重要的!


调试运行时代码


当你的代码出现错误或意外行为需要开始调试的时候,你的目光可能就会投向开发工具中的“源代码”选项卡了。我们将深入探讨其中的一系列应用场景。



断点


当你要调试某行代码时,你习惯的做法可能就是看日志。现在我要介绍一种更强大的方法,更专业也更深入:也就是断点


一般来说调试的第一步就是设置断点。大多数浏览器内置的开发工具都允许正在调试的页面停止在某行代码上,或是停止在特定语句上;本文则只介绍 Chrome 开发工具的情况。


什么是断点?


一般来说,我们需要让代码在某处停止运行,以便交互地检查我们感兴趣的特定上下文。


一旦代码在断点处停止,我们就可以访问作用作用域、浏览调用堆栈,甚至更改运行时代码来调试了。


如何设置断点?


为了举例说明问题,我们会调试一段 Angular 代码,这段代码出自我开发的一个教育用途的小项目。当然我具体使用什么技术并不重要。


  • 首先打开开发工具并转到“源代码”选项卡

  • 然后打开我们想要调试的文件


提示:在 Mac 上用⌘+ O 打开文件选择器;在 Windows 上使用 CTRL + O


  • 打开文件后,我们单击要停止的代码行来设置断点。



设置断点


如上图中所示,除了在某行代码上设置断点外,我们也可以把断点设置在这行代码的语句上。


我们设置了 3 个断点:


  • 第一个断点会让程序在指定位置停止运行。

  • 第二个断点会让程序在priceReceived函数执行之前停止运行。

  • 第三个断点会让程序在priceReceived被调用后立即停止,这样我们也可以检查箭头函数的返回值了。


调用箭头函数时程序将停止运行,右侧面板的 Scope 将用当前上下文相关的信息填充,并赋予我们访问所有作用域的权限,这样我们就能检查感兴趣的值了。


本示例中,我们就能看到变量 price 的值。



分析当前作用域


在下图中,一旦执行了 priceReceived 函数就会触发我们设置的第三个断点。


如右侧面板所示,Return value 将向我们显示匿名函数返回的内容



分析匿名函数的 Return Value


临时暂停断点


场景:你在代码库中设置了一堆断点。


调试时多次刷新页面是很常见的事情,你可能早就习惯了。


我们调试的代码可能有各种各样的断点,有时甚至能调用数百次之多!的确,这种情况又费时间又让人头疼不已。


所以我建议在这种情况下暂停所有断点的执行,可以点击下图所示的图标来执行该操作:



停用所有断点


出现错误时停止执行


场景:你遇到了意外错误,但又不想设置断点,因为你不知道错误会在什么时候抛出。


你可以在抛出错误时立即停止程序执行,这样就可以检查作用域并搞清楚问题所在了。



出现异常时暂停


条件断点


顾名思义,条件断点允许我们仅在某条件为真时触发某些断点。


例如,在上面的示例中用户可以在文本区作用域中输入非数值的值。JS 非常宽容,这时只会显示 NaN 而不是抛出错误。


场景:你的代码比这个例子还要复杂,你还无法确定结果何时会变为 NaN。


当然你可以设置一个断点,但重现错误也不容易,一步步执行代码搞不好要花上半个小时。在这种情况下你可以使用条件断点,仅在检查到的值为 NaN 时中断程序执行。


见下图:



条件断点:


  • 右键单击要添加断点的代码行。

  • 单击“添加条件断点…”。

  • 添加有效的JS表达式。当然,调用表达式时你也能访问访问作用域,这意味着我们可以引用参数x和y。

  • 当表达式为真时就会触发断点!


单步执行代码


开发工具可以帮助我们快速单步执行代码,无需在每一行都设置断点。


  • 单步执行(Step


这是开发工具最简单的导航器,允许你基于程序执行顺序逐行执行代码。


Step 是最近才引入的功能,是“单步执行下一个函数调用(Step Into next function call)”功能改动的产物。在调试异步代码时,Step 功能将按代码的时间顺序逐行执行。



单步执行


  • 跳过下一个函数调用(Step over next function call


这个导航器允许你在逐行执行代码时无需执行函数调用。也就是说函数调用都会被跳过去,除非在它们中设置了断点,否则调试器不会停在函数的语句上。



跳过下一个函数调用


如上图所示,multiplyBy 和 renderToDOM 都执行了,但调试器没有在它们那里停下来。


  • 执行到下一个函数调用(Step into next function call


Chrome 68 开始这个导航器的行为有了改动。它与之前提到的 Step 类似。不同之处在于,调试异步代码时前者将停止在异步代码上,而非按时间顺序运行的代码上。



执行到下一个函数调用


观察上图:按时间顺序,第 32 行代码应该已经运行了;但实际情况是调试器等了 2 秒后移动到了第 29 行。


  • 跳出函数调用(Step out of function call


假设你对某个函数不感兴趣,这个导航器允许你跳出一个函数并在函数调用后的下一行停止



跳出函数调用


上图中发生了什么?


  • 我们在第36行的断点停了下来。

  • 我们退出了函数renderToDOM。

  • 调试器直接移到第29行,跳过了函数renderToDOM的剩余部分。


全局变量和即刻求值


有时需要在全局作用域内存储某些值(例如组件类,大型数组或复杂对象)。


例如,当你想要使用不同参数调用该组件上的方法时,可以在调试时将这些值添加到全局作用域,节约很多时间。



从当前作用域设置全局变量


在上图中,我将数组[previous,current]保存为全局变量。开发工具自动为变量指定一个名称 temp{n},其中 n 基于先前保存的变量数量。


如上图所示,变量被命名为 temp2,因为它已经被全局定义了,所以我就能在控制台中使用它了!


即刻求值(Eager Evaluation)是 Chrome 68 中发布的一项功能,开发工具会在你写下语句后立即在控制台中对语句求值,并显示方法的签名。


观察上图,当我将保存的变量映射到字符串数组时,不必按下回车也能立即看到结果。


浏览调用堆栈


浏览调用堆栈是开发工具中最有用的工具之一:你不仅可以在调用堆栈中来回跳转,还可以对每个步骤检查作用域。


假设我们有一个简单页面和一个输入数字的脚本,脚本会在页面上呈现输入数字乘以 10 的结果。我们将调用两个函数:一个用来计算乘法,一个用来将结果呈现给 DOM。



浏览调用堆栈


如上图所示,只需单击“调用堆栈”窗格中的函数名称就可以浏览调用堆栈。


此外,每次我们从一个调用跳转到另一个时作用域都会保留,我们可以对它逐步分析!


屏蔽脚本以简化堆栈


屏蔽脚本会从堆栈中排除某些脚本,或排除匹配某种模式的脚本,让调用堆栈更简洁。


例如如果我只想调试 userland 代码,我会加入一个模式,把文件夹 node_modules 下面的所有脚本都屏蔽掉。


有两种方法可以屏蔽一个脚本:


  • 右键单击源代码面板中的脚本,然后单击“Blackbox Script”。

  • 转到Chrome设置页面,然后转到Blackboxing并单击Add Pattern …输入你的屏蔽模式,适合用来大批量屏蔽脚本。



屏蔽 node_modules 文件夹


监视表达式


监视表达式功能可以让开发工具跟踪和执行一些 Javascript 表达式,并显示当前结果。这个工具很有意思,你可以虚拟地随便写点内容,只要它是一个有效的 Javascript 表达式就行。


例如,你可以编写一个表达式并期望它的结果始终为 true,这样当表达式为 false 时,你就知道当前状态有问题。


要点:


  • 当我们使用断点调试时,监视表达式将实时求值,不需要刷新。

  • 如果代码正在执行,则需要手动单击刷新按钮。



结语


Chrome 开发工具很适合调试复杂代码。有时只看控制台日志是不够的,用上述工具能更深入地调试代码。这些工具需要一些练习才能熟练使用,所以一开始手生的话请多点耐心。


资源


这些资源能帮助你更好地了解开发工具选项



英文原文:https://blog.bitsrc.io/debugging-javascript-like-a-pro-a2e0f6c53c2e


2019 年 7 月 02 日 00:173909

评论

发布
暂无评论
发现更多内容

工作10年后,再看String s = new String("xyz") 创建了几个对象?

艾小仙

Java 面试 编程语言 JVM

架构师训练营第 1 期第一周总结

Geek_a01290

极客大学架构师训练营

「架构师训练营第 1 期」第一周作业 (作业二)

Geek_83908e

极客大学架构师训练营

架构师第一周

Geek_Gu

极客大学架构师训练营

课程大作业

小胖子

我搭建了一套企业级私有Git服务,抗住了每天上万次攻击!

冰河

git 代码管理 代码仓库 私有服务 远程协作

架构师训练营-第一周命题作业

咖啡

# 架构师训练营Week1作业

lggl

极客大学架构师训练营

第一周命题作业

BOBBB

git 常用操作及 git 工作流介绍

hepingfly

git git分支操作 git工作流

week-1-part1 食堂就餐卡系统设计

451409827

极客大学架构师训练营

架构师训练营学习笔记

Erwa

第一周:学习总结

BOBBB

第1周 作业

wgl

UML

SpringBoot系列(1)-初识SpringBoot

引花眠

springboot 学习总结

ARTS打卡 第17周

引花眠

微服务 ARTS 打卡计划

架构师训练营第 1 期第一次作业

Geek_a01290

极客大学架构师训练营

极客时间架构 1 期:第 1 周架构方法 - 命题作业

Null

架构师训练营第一周总结

知鱼君

极客大学架构师训练营

# 架构师训练营Week1总结

lggl

极客大学架构师训练营 UML

第1周 作业

Pyr0man1ac

【架构师训练营1期】第一周作业

诺乐

架构师训练营第一周课程笔记及心得

Airs

ARTS Week17

时之虫

week1 架构方法总结

zero2onemore

week-1-part2 学习总结

451409827

初学架构方法

Zzzz

极客大学架构师训练营

Week_01学习总结

golangboy

「架构师训练营第 1 期」

架构师训练营1期-WEEK01-作业

Geek.Kwok

极客大学架构师训练营

第一周总结

_

极客时间 架构师 极客大学架构师训练营 第一周总结

架构师第一周笔记

Geek_Gu

JavaScript调试专家指南:帮你更好、更快地调试代码-InfoQ