1. 前言
在很长一段时间,JavaScript 就像是一种玩具语言,在浏览器端提供表单验证、弹框之类的小功能,与其他语言相比如Java、C++显得很不专业。 没有好的调试工具就是 不专业 非常典型的体现。
笔者初学 JavaScript 是在2009年,那时候 Ajax 开始流行,IE6 是用户量最高的浏览器。但是 JavaScript 的调试体验非常糟糕,总结起来三大招。

-
第一招:掐指算
-
第二招:alert
-
第三招: 删代码
但也奇怪,早年养成的不良调试习惯,居然受用至今。
掐指算 说白了就是通过个人经验判断,代码写多了、遇到问题多了,很多问题和bug凭直觉就能猜个大概。(这个在今天依旧很受用)。
alert 在今天看来很费力、费时、调试体验糟糕。但很多特殊开发环境下,比如在第三方客户端(像微信、微博等)webview 中开发H5,一般这些客户端不会开放客户端调试功能,用 HTTP代理 + alert 差不多是最短平快的手段。
删代码 在异步编程中遇到出现死循环、执行顺序混乱,当自己一头雾水开始怀疑人生的时,在 if/else中大刀阔斧砍一刀,总是有奇效,经常能发现问题。
当然,以上带有戏谑,事实上当我发现原来 Visual Studio 可以通过附加进程调试 IE6 中的 JavaScript 时, 是极为激动的。
所谓 工欲善其事,必先利其器,从后来的 firebug 到之后 Chrome Dev Tool, JavaScript 的调试体验越来越好。 随着 单页面应用 和 雨后春笋的前端 MVC 框架发展,JavaScript 也从一门不起眼的玩具语言发展成真正的工业级语言。
2. 准备工作
下面,我们主要来聊一下 NodeJS 的调试。NodeJS 刚出来时候,调试也是一大诟病,到今天,NodeJS 的调试工具已经非常丰富。 不过,笔者今天分享的内容主要基于 IDE 来调试,JetBrains 家的 IDE 都支持 NodeJS 的调试。常见的比如
-
Webstorm - The Smartest JavaScript IDE
-
IntelliJ IDEA - Capable and Ergonomic IDE for JVM
-
Phpstorm - Lightning-smart PHP IDE
本文以 IntelliJ IDEA 演示,一般JetBrains 的 IDE 安装时,会建议勾选 NodeJS 插件。可以通过【Preferences】-【Plugins】中检索NodeJS 查看是否安装。

下文中用的素材和代码说明如下
-
Koa@2.5.1 https://github.com/koajs/koa/tree/2.5.1 - Koa是目前基于NodeJS最常用的web框架
-
Koa-examples https://github.com/koajs/examples - Koa官方提供的示例代码
-
create-react-app@1.1.4 https://github.com/facebook/create-react-app/tree/v1.1.4 - React工程生成器
3. 使用 IntelliJ IDEA 调试 NodeJS
下面我们将演示如何用 IntelliJ IDEA 进行 NodeJS 调试。
在 IntelliJ IDEA 中的 NodeJS 插件,对 Node、 Jest 调试都有很好的支持,几乎是零配置。
我们先下载 Koa 的 2.5.1 版本,展看目录格式如下
.
├── benchmarks
├── coverage
├── docs
├── lib
├── node_modules
└── test
其中,test 文件夹中是 Koa 的单元测试代码。优质的 JavaScript 开源项目,几乎都有完整的单元测试代码。
如果你是一个实战派,讨厌循规蹈矩的学习框架的文档,那么单元测试的用例几乎是学习框架最快的示例代码了,既可以窥探这个框架的所有功能点,又可以学习到如何使用。
3.1 添加断点
我们进入 Koa@2.5.1 工程的 test/application/index.js 文件
-
在第
12行左侧,单击添加 断点(breakpoint) -
在第
9行,右键选择 Debug should handle ... 启动调试
如下图

想要删除断点,很简单只需要再点击下断点就可以取消
3.2 条件断点
条件断点,只需要在断点的红点处右键,即可以设置条件断点

3.3 异常断点
JetBrains 的 IDE 有非常好用的异常断点工具。
打开 Debug 窗口

简单解释一下它的配置参数
-
Suspend : 很容易理解,就是在异常时,暂停住
-
Log to console : 确定是不是把异常信息和堆栈信息打印到控制台中
-
Uncaught only : 如果选上,则是只在 未捕获异常 进行断点。JavaScript 中的异常有两种,一种是 未捕获异常,一种是 捕获异常的,区分很简单就是有没有 try/catch 或者是全局异常处理函数处理异常。
3.3.1 异常断点示例
打开 koajs/examples 工程,进入 errors/app.js 文件。大致的代码如下。

在 app.use 的处理函数中抛出一个异常,同时在error 中捕获了异常,服务启动在 3000 端口。 按照上面讲的,这种是 捕获异常, 如果在异常断点中配置 Uncaught only 是无法断点的。
我们先写一个客户端请求代码(其实直接用浏览器访问也可以)。 在 IntelliJ IDEA 原先有一个 Test RESTful Web Service的工具,就跟 PAW、PostMan类似,可以模拟接口请求。 在最新版的IntelliJ IDEA建议直接写 HTTP 请求。这个功能非常赞。
在 error 文件夹上,【右键】-【New】-【HTTP Request】


要调试一段 NodeJS 的代码,直接打卡文件右键,选择 Debug 就可以。如下面演示

3.4. 单步调试
IntelliJ IDEA 对 NodeJS 的单步调试,与Chrome Dev Tool 中的相似,所有功能都集成在 调试工具窗口(Debug) 中。

支持
-
Step Over(单步跳过) - 跳过一个代码块或函数调用
-
Step Into(单步进入)- 进入一个代码块或被调用的函数内部
-
Step Out(单步跳出)- 跳出一个代码块或函数体
另外,Show Exception Point(查看异常点) 功能非常实用,可以跳转到当前中断代码处。尤其在大的工程要频繁阅读代码,点一下可以快速回到中断代码处。
3.4.1 单步调试示例
打开 koajs/examples 工程,进入 blog/app.js 文件。大致的代码如下。

上面的代码路由表如下
| method | path | 含义 |
|---|---|---|
| GET | / | 博客列表 |
| GET | /post/new | 新建博客页面 |
| GET | /post/:id | 显示某篇博客 |
| POST | /post | 创建博客接口 |
我们先按照这个路由表,通过 IntelliJ IDEA 的 HTTP Request 做好请求模拟.代码如下

我们单步调试一下创建博客接口,看一下博客是如何生成的。

3.4.2 单步进入第三方函数
默认情况下,单步调试是不会进入 node_modules 中第三方库的函数中。但有时候,可能问题就在第三方库的函数中。可以通过 Force Step Into(强制单步进入) 实现。 例如,上面的代码,我们单步跟进了 create 函数, Step Into 是不会进入到ctx.redirect 函数。我们尝试进入
ctx.redirect 看下 Koa 是如何实现这个函数的。

3.5. 查看和移动调用栈
有时,我们需要看一下函数的调用栈。可以通过 Frames 直观的查看和移动。仍旧以上面 create 函数为例,我们想了解下,是如何调用到 create 函数的。

我们看到,虽然 blog/app.js 中的代码虽然不多,但是 create 函数的调用栈缺特别深。

但是,其中很多函数是 Koa 和 NodeJS 的库函数,我们相关性不大。我们可以通过过滤库函数,来看下 create 的调用栈。

原来,与业务相关的起始代码是 app.listen(3000)
3.6. 查看和监视变量
这个比较简单

-
在 Variables 区域会显示整个作用域
-
将鼠标移到代码中的变量上也会提示当前变量的值
4. 自定义调试配置
我们通过在单元测试的代码或是在源码中右键选择Debug,IntelliJ IDEA会自动生成一个调试配置。一般情况下,默认的调试配置就满足我们配置的需要。

如果,大家需要修改某些环境变量或是Node参数,可以在

修改或添加即可。
这里说一种特殊的配置,在 npm 的 package.json 中启动调试
4.1 npm调试配置
比如下面是基于 create-react-app 生成的一个工程 my-app,我们想调试一下它的 start 开发配置代码。

直接点击左侧的箭头,【Debug 'start'】。这时,代码会运行,但 Console 会提示修改配置

我们需要按照它的提示修改配置,但首先要找到 react-scripts 代码在哪里。它其实是 node_modules/react-scripts/bin/react-scripts.js文件。我们在其中添加一个断点。
在 package.json 中添加一个配置。

即可实现在 npm 的 package.json 中实现调试。
5. 调试是一门艺术而非科学
《软件调试的艺术》一书中讲到,调试是一门艺术而非科学。 本文主要讲的都是工具的使用,但工具和经验都是双刃剑,很有可能你开足了马力搭好环境、单步跟进、九死一生终于找到了 小强(bug) 原因所在。 大神通过掐指神算,早把问题解决掉了。
谨记
不以物喜 不以己悲
6. 参考
-
《软件调试的艺术》 - Norman Matloff / Peter Jay Salzman ,人民邮电出版社,2009
-
《Node.js硬实战:115个核心技巧》 - Alex R. Young / 【美】Marc Harter ,电子工业出版社, 2017
-
Intellij IDEA 2018.1 Help - NodeJS - https://www.jetbrains.com/help/idea/developing-node-js-applications.html
