使用 ndb 调试你的 Node.js 项目

头图

代码调试按照调试方式大致分为日志(Log)断点(Breakpoint)两种办法。其中日志就是手动的在代码中增加日志打印获取过程信息来判断问题。这种方法的好处是调试简单,一个对业务熟练的工程师通过线上良好的日志记录可以非常快的发现业务问题。但是它的缺点也非常明显,获取的内容比较单一,动态调试需要不断的在业务中增加日志打印代码。

于是乎断点调试出现了。断点调试类似于中医的望闻问切,我们通过在需要观察的点打上断点就能详细的获取到程序运行到该点时的所有上下文,并利用单步调试逐一观察程序运行状况,准确判断出问题的地方。另外利用 Chrome DevTool 我们也可以随时对线上业务进行调试,可以说是非常方便了。

V8 Inspector

在前端使用 Chrome DevTool 进行断点调试已经是非常成熟了,在 Node.js(6.3+) 中也自带了一个类似的调试器,主要是在 Node 内部实现了一套 v8 调试器通信协议。启动的时候添加 --inspect 参数,我们就能得到 Chrome DevTools 调试界面了,剩下的调试过程就和正常的 Chrome 调试是一样了。

1_32J7CSAzBtm68CwiVS0Ukw.png

:Users:lizheming:Desktop:1_-W3U7eUzBnnDu6dTlx9TnQ.jpg

使用 --inspect 调试极大的方便了 Node.js 开发,让服务端调试也有了类似前端调试一样的体验。除了直接打开 DevTools 调试,VSCode, WebStorm 等开发工具也将其集成到了编辑器中,不过内部的原理是类似的。不过人无完人,在使用过程中 Node Inspector 调试也存在着一些缺点:

  • 需要在 node 命令后增加 --inspect 参数,对于一些第三方命令启动无法直接支持调试,例如 webpack, ava, mocha...
  • 多进程调试非常的麻烦,特别是子进程频繁的销毁的时候,需要外部手动的监听进程的创建并手工将进程和调试工具进行通信对接

注: 虽然 VSCode 使用的是 Inspector Protocol 模式,不过在 1.22 的版本中已经能够自动绑定多进程监听端口了,具体的话可以查看天猪大大的《VSCode 调试 Egg 完美版》

ndb

两周前 Chrome 实验室开源了一款新的调试工具,也就是我们今天的主角 —— ndb。它提供了更良好的调试体验,正如官方仓库所说,它为我们带来了如下一些特性:

  1. 子进程自动检测和调试接入
  2. 支持在模块加载前进行断电
  3. 支持在调试工具中直接编辑文件,保存后自动更新到本地文件
  4. 默认情况下,ndb 会对引用的所有项目文件夹外的脚本开启黑盒模式让我们能更专注业务代码。项目文件夹外的脚本包括 Node.js 自带的模块文件(例如 _stream_wrap.js, async_hooks.js, fs.js 等)。当然你可以在设置中修改“Blackbox anything outside working dir”配置来关闭这个功能。

安装

npm install -g ndb

首先要确保你的 Node.js 环境 >= 8.0.0,然后使用 npm install 就可以非常方便的完成安装。由于 ndb 依赖 Puppeteer 安装过程中会去下载 Chromium 所以下载过程可能会有一定的时间,请各位同学耐心等待。如果有碰上权限问题官方提示可以尝试增加 --unsafe-perm=true --allow-root 参数解决。

使用

不同于 node --inspect 的复杂使用,ndb 的使用方式非常的简单。在所有你想要进行调试脚本执行前加入 ndb 命令即可,甚至还能直接使用 ndb 命令启动脚本。以下是从仓库示例中引用的一些启动方式:

ndb node server.js

ndb npm run test

ndb mocha

ndb .

--inspect 一样,执行命令后就会弹出 Chrome DevTools 调试界面。在这个特制的调试界面中,你可以:

  • 断点调试,异步方法单步调试
  • 控制台预执行显示(需要 Node.js >= 10)
  • JS 样本分析
  • 内存分析
  • 本地终端

使用 ndb 进行 ThinkJS 调试

下面以基于 ThinkJS 开发的 Node.js 项目 Firekylin 为例,简单看看如何使用 ndb 进行断点调试。

可以看到基本上调试的流程非常的简单,并且自动适配了多进程项目(视频中启了8个进程),解决了之前使用 --inspect 的两个问题。另外在底部的控制台由于是 REPL 环境,可以实时获取到断点处当前环境的数据,例如我们可以打印 process.memoryUsage() 查看当前的内存使用情况。

除了断点调试之外,ndb 也支持内存和性能分析,可以帮助我们分析内存泄露和。具体的也可以参考一下官方文档《Chrome DevTool 解决内存问题》

ndb 的问题

还是那句话人无完人,ndb 目前使用下来还是觉得有一点不太舒服的地方。主要是表现在文件更新方面,目前代码编写还是在代码编辑器中,调试需要到 ndb 界面上,频繁的切换感觉有点不爽。希望后续 VSCode 能尽快将 ndb 引入替换现有的调试工具就非常方便了。

有同学会说为什么不在 ndb 上直接编辑文件呢,毕竟支持文件编辑保存也是 ndb 作为调试工具的一大特色。这是因为在多进程环境下每个进程的调试是相互独立的,你在一个进程上的文件修改只能反映在这个修改的进程上,不能在所有进程上生效,和我们本地操作文件不太一样,使用上需要注意。不过这个也比较好解决,调试的时候只开启一个进程就可以了。

后记

Node.js 已经有越来越多的工具可以帮助我们进行断点调试了,从早期的 Debug Protocol 到前两年开始支持的 V8 Inspector Protocol 到现在的 ndb,我们看到了技术正在一步步的朝前走着,当然我们这里需要先感谢下 Chrome 工程师们,感谢他们开发出了这么棒的工具。当然除了断点单步调试之外,日志调试也有它存在的必要,两者可以相辅相成没有孰好孰坏之分。

最后,送一张图给大家祝大家新的一周改BUG顺利~

改bug

参考资料:

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注