Node.js 调试一路走来经历了什么

开发 前端
今天我们用 Chrome Devtools 或者 VSCode Debugger 都可以轻松调试 Node.js 代码,其实这背后还是有一段挺有意思的故事的。

做为前端开发,想必大家都写过 Node.js 的代码,也大概率用 debugger 断点调试过。

我们可以用 Chrome Devtools 调试 Node.js 代码,也可以用 VSCode 来调试它。调试工具是 Node.js 开发的基础工具了。

但现在好用的调试工具也不是一开始就这样的,它经历了一系列的演变过程。今天我们就来聊聊 Node.js 调试工具背后的故事吧。

相信还是有部分同学不知道 Node.js 代码怎么调试的,所以我们先来过一遍怎么调试 Node.js 代码:

调试 Node.js 代码

准备一段简单的 Node.js 代码用来调试:

const os = require('os');
function func(a, b) {
return a + b;
}
console.log(func(1,2));
console.log(os.cpus());

它的逻辑就是执行了一个加法,然后打印了 cpu 的核心的情况。

直接执行是这样的:

打印了 1 + 2 的结果,也就是 3 ,也打印了 CPU 核心的情况,8 核的 M1 芯片。

那怎么断点调试呢?

执行的时候加上一个 --inspect 的参数,就会启动调试服务了:

指定 --inspect-brk 参数还会在首行断住。

可以看到启动了一个 WebSocket 的服务端,这就是调试服务,用某个调试工具客户端连上就行了:

调试客户端可以是 Chrome Devtools 也可以是 VSCode。

Chrome Devtools

比如用 Chrome Devtools 来连上是这样的:

打开 chrome://inspect 的 url 就会看到这个可以连接的 target:

点击 inspect 就是连上这个 ws 服务端来做调试:

右边可以看到调用栈、上下文的变量,可以单步执行、可以打断点等。

打印信息会输出在 console:

VSCode

用 VSCode 调试的话需要在项目根目录下加一个 .vscode/launch.json 的文件,类型选择 attach to process:

很容易理解,就是连接到目标进程的 ws 服务的意思:

端口是 9229,也就是我们调试服务启动的端口。

然后点击调试面板的调试按钮来启动:

这样也会在断点处断住,可以单步运行、可以看调用栈、上下文的信息:

看到这里不知道有没有同学会觉得这样太麻烦了,每次都要起一个 ws 调试服务,然后再 attach,不能把这两步合并到一块自动给做了吗?

没错,确实可以合并到一块,也就是起一个 ws 服务,然后自动 attach 上:

调试配置选择 launch program:

只需要指定要调试的 Node.js 模块的地址,然后点击启动,这样就可以调试了:

注意,想达到和 --inspect-brk 一样的首行断住的效果,这里要执行 stopOnEntry 为 true。

效果是一样的:

这样比直接启动 ws 调试服务,然后再 attach 还少了一步。

怎么调试 Node.js 讲完了,大家是不是觉得这样调试还是蛮方便的呢?

但其实最开始的调试并没有这么好用,接下来我们看下之前的调试都是咋样的吧:

Node.js Debugger 的历史

从前面的实践中我们也能发现,调试的原理还是蛮清晰的:

启动一个 WebSocket 服务端来提供各种运行时的信息,这个服务是 JS Runtime 提供的,也就是 Node。

启动一个 WebSocket 客户端来实现调试的 UI,包括调用栈、上下文的显示、打断点、单步运行等功能,比如我们用过的 Chrome Devtools、VSCode Debugger。

中间传输的消息就是调试协议:

我们知道 Node.js 是基于 V8 的,V8 本身有调试协议 V8 Debug Protocol,所以 Node.js 最早的调试协议也就是 V8 Debug Protocol。

当时调试是这样的:

通过 node debug 来跑 js 文件,会在首行断住:

然后可以通过 run、cont、next、step 等命令来实现单步调试,通过 backtrace 打印调用栈,通过 setBreakPoint 等设置断点:

比如用 setBreakPoint(sb)命令在第四行打个断点:

然后 cont(c) 命令继续执行,backtrace(bt) 打印调用栈:

虽然该有的调试功能都有,但是这样调试还是比较费劲的。

怎么能不用命令行调试,而是用 UI 来调试呢?

当时 Node 就瞄准了 Chrome Devtools,它的调试 UI 就很不错。

但是 Chrome Devtools 的调试协议是 Chrome Devtools Protocol,和 V8 Debug Protocol 还是有些差距的,怎么能用上 Chrome Devtools 的调试工具来调试 Node 呢?

其实还挺容易想到的,就是加一个中间的服务来做转换:

这个服务是 node-inspector 这个包提供的。

所以当时 node debug 服务跑起来之后,还要要再跑一个 node-inspector 服务,这样才能用 chrome devtools 来调试 Node.js 代码。

后来维护 Node.js 的那些人觉得这样也太麻烦了,要不让 Node.js 提供的调试协议就直接就是兼容 Chrome Devtools Protocol 的吧。

当时就有了这样一个 pr,把 v8 inspector 集成到 Node.js 中:

这个 v8 inspector 就是从 chrome 的内核 blink 里剥离出来的让 v8 支持 chrome devtools protocol 的部分。

很明显这需要 v8 团队的配合,所以说 Node.js 的发展还是很依赖 v8 团队的支持的。

之后 Node.js 就在 v6.3 中加入了这个功能:

并且在成熟之后去掉了对 v8 debug protocol 的支持,也就是废弃了 node debug 命令,改为了 node inspect。

启动 ws 服务的方式就是 node --inspect 或者 node --inspect-brk。

当然,之前作为两个协议的中转的服务 node-inspector 也就退出了历史舞台。

所以今天,我们可以轻易的用 Chrome Devtools 来调试 Node.js 代码,就如本文开始展示的那样。

当然,这里只是说 Chrome Devtools 调试 Node.js,在 VSCode 里调试 Node.js 的话还有另一段小故事:

调试的原理我们已经知道了,就是 ws 客户端和服务器的通信,然后基于调试协议来完成不同的功能。Node.js 是这样,其他语言也是这样。

VSCode 是一个通用的编辑器,是要支持多种语言的,也就是它的调试 UI 要支持多种调试协议。

要同一个调试工具同时支持不同的协议有点不太现实,那怎么办呢?

可以加一个中间层,VSCode 的调试 UI 只要支持这个中间的调试协议就可以了,其余的调试协议适配到这个调试协议上来:

这就是 DAP 协议,debugger adpater protocol。

Node.js 在把调试工具的协议换成兼容 Chrome Devtools Protocol 的协议之后,只要实现个 DAP 的 adapter 就可以对接到 VSCode 的调试工具了。

这样我们就可以在 VSCode 里调试 Node.js 了。

Node.js 调试的故事讲完了,我们来总结下:

总结

现在 Node.js 的调试可以用 Chrome Devtools 也可以用 VSCode,都是挺方便的。

但是它不是一开始就这么好用的,我们聊了下它之前的故事:

调试的原理就是 Node 启动 ws 的调试服务,调试客户端(chrome devtools、vscode 等)对接这个调试服务并实现交互的 UI,基于传输的调试协议来完成调试。

最开始 Node.js 的调试协议是 v8 debug protocol,只能用命令行调试。

为了直接用 Chrome Devtools 的 UI 来调试,就实现了 node-inspector 的中转服务来实现 v8 debug protocol 到 chrome devtools protocol 的协议转换。

这样还是太麻烦了,所以后来 Node.js 和 v8 团队合作实现了 v8-inspector,可以让 Node.js 提供的调试协议是直接兼容 Chrome Devtools Protocol 的。

这样我们就可以直接用 node --inspect 起 ws 调试服务,然后用 Chrome Devtools 连接调试了。

VSCode 为了同一个调试 UI 支持不同语言的调试,设计了中间的调试协议 Debug Apapter Protocol。Node.js 想在 VSCode 里调试的话只要实现对应的 adapter 即可。

今天我们用 Chrome Devtools 或者 VSCode Debugger 都可以轻松调试 Node.js 代码,其实这背后还是有一段挺有意思的故事的。

责任编辑:姜华 来源: 神光的编程秘籍
相关推荐

2012-02-02 15:14:29

Node.js

2011-09-02 14:47:48

Node

2011-03-28 10:52:51

戴尔高效企业

2021-08-25 06:33:52

Node.jsVscode调试工具

2016-02-02 17:10:46

戴尔Equal Logic

2012-05-02 15:56:20

PHP

2015-03-10 10:59:18

Node.js开发指南基础介绍

2013-11-01 09:34:56

Node.js技术

2021-08-24 05:00:21

Nodejs线程

2023-01-30 22:34:44

Node.js前端

2023-08-29 09:43:21

Node.js.env

2019-05-27 15:30:44

Node.jsJavaScript前端

2017-04-18 09:27:14

Visual StudNode.js调试

2010-04-29 13:04:39

Google数据中心

2015-10-22 17:41:32

路友

2011-09-08 13:46:14

node.js

2011-09-09 14:23:13

Node.js

2011-11-01 10:30:36

Node.js

2012-10-24 14:56:30

IBMdw

2011-11-10 08:55:00

Node.js
点赞
收藏

51CTO技术栈公众号