NodeJS 调试不权威指南

2,763 阅读8分钟
原文链接: mp.weixin.qq.com

1. 前言

在很长一段时间,JavaScript 就像是一种玩具语言,在浏览器端提供表单验证、弹框之类的小功能,与其他语言相比如JavaC++显得很不专业。 没有好的调试工具就是 不专业 非常典型的体现。

笔者初学 JavaScript 是在2009年,那时候 Ajax 开始流行,IE6 是用户量最高的浏览器。但是  JavaScript 的调试体验非常糟糕,总结起来三大招。

  • 第一招:掐指算

  • 第二招:alert

  • 第三招: 删代码

但也奇怪,早年养成的不良调试习惯,居然受用至今。

掐指算 说白了就是通过个人经验判断,代码写多了、遇到问题多了,很多问题和bug凭直觉就能猜个大概。(这个在今天依旧很受用)。

alert 在今天看来很费力、费时、调试体验糟糕。但很多特殊开发环境下,比如在第三方客户端(像微信、微博等)webview 中开发H5,一般这些客户端不会开放客户端调试功能,用  HTTP代理 + alert 差不多是最短平快的手段。

删代码 在异步编程中遇到出现死循环执行顺序混乱,当自己一头雾水开始怀疑人生的时,在 if/else中大刀阔斧砍一刀,总是有奇效,经常能发现问题。

当然,以上带有戏谑,事实上当我发现原来 Visual Studio 可以通过附加进程调试 IE6 中的 JavaScript 时, 是极为激动的。

所谓 工欲善其事,必先利其器,从后来的 firebug 到之后 Chrome Dev ToolJavaScript 的调试体验越来越好。 随着 单页面应用 和 雨后春笋的前端 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 插件,对 NodeJest 调试都有很好的支持,几乎是零配置。

我们先下载 Koa 的 2.5.1 版本,展看目录格式如下

.
├── benchmarks
├── coverage
├── docs
├── lib
├── node_modules
└── test

其中,test 文件夹中是 Koa 的单元测试代码。优质的 JavaScript 开源项目,几乎都有完整的单元测试代码。

如果你是一个实战派,讨厌循规蹈矩的学习框架的文档,那么单元测试的用例几乎是学习框架最快的示例代码了,既可以窥探这个框架的所有功能点,又可以学习到如何使用。

3.1 添加断点

我们进入 Koa@2.5.1 工程的 test/application/index.js 文件

  1. 在第12行左侧,单击添加  断点(breakpoint)

  2. 在第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的工具,就跟 PAWPostMan类似,可以模拟接口请求。 在最新版的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. 自定义调试配置

我们通过在单元测试的代码或是在源码中右键选择DebugIntelliJ 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. 参考

  1. 《软件调试的艺术》 - Norman Matloff / Peter Jay Salzman ,人民邮电出版社,2009

  2. 《Node.js硬实战:115个核心技巧》 - Alex R. Young / 【美】Marc Harter ,电子工业出版社, 2017

  3. Intellij IDEA 2018.1 Help - NodeJS - https://www.jetbrains.com/help/idea/developing-node-js-applications.html