学习 nodejs 最重要的是什么?可能每一个人都有本身的答案。javascript
我以为学习 nodejs 除了要掌握基础的 api、经常使用的一些包外,最重要的能力是学会使用 debugger。由于当流程复杂的时候,断点调试可以帮你更好的理清逻辑,有 bug 的时候也能更快的定位问题。java
狼叔说过,是否会使用 debugger 是区分一个程序员 nodejs 水平的重要标志。node
本文分享一下 debugger 的原理和 vscode debugger 的使用技巧。程序员
运行 nodejs 代码的时候,若是带上了 --inspect
(能够打断点) 或者 --inspect-brk
(能够打断点,并在首行断住) 的参数,那么就会以 debugger 的模式启动:web
能够看到,node 启动了一个 web socket 的 server,地址是:ws://127.0.0.1:9229/78637688-e8e0-4582-80cc-47655f4bff66chrome
为何 debugger 要启动一个 websocket server 呢?express
debugger 的含义就是要在某个地方断住,能够单步运行、查看环境中的变量。那么怎么设置断点、怎么把当前上下文的变量暴露出去呢,就是经过启动一个 websocket server,这时候只要启动一个 websocket client 链接上这个 server 就能够调试 nodejs 代码了。json
连上以后呢,debugger server 和 debugger client 怎么交流?这就涉及到了 v8 debug protocol。api
经过两边都能识别的格式来交流,好比:websocket
在 test.js 的 100 行 设置断点:
{
"seq":118,
"type":"request",
"command":"setbreakpoint",
"arguments":{
"type":"script",
"target":"test.js",
"line":100
}
}
复制代码
而后查看当前做用域的变量:
{
"seq":117,
"type":"request",
"command":"scope"
}
复制代码
执行一个表达式:
{
"seq":118,
"type":"request",
"command":"evaluate",
"arguments":{
"expression":"a()"
}
}
复制代码
以后继续运行:
{
"seq":117,
"type":"request",
"command":"continue"
}
复制代码
经过这种方式,client 就能够告诉 debugger server 如何执行代码。
debugger client 通常都是有 ui 的(固然,在命令行里面经过命令来调试也能够,但通常不这么作)。常见的 js 的 debugger client 有 chrome devtools 和 vscode debugger 等。
咱们写一个简单的 js 脚本,经过 node --inspect-brk 跑起来:
能够看到它启动在了 9229 端口,
而后,咱们分别经过两种 client 连上它。
在 chrome 地址栏输入 chrome://inspect,而后点击 configure 来配置目标端口:
把刚才的端口 9229 填上去:
而后就能够看到 chrome 扫描到了这个 target,点击 inspect 就能够连上这个 debugger server。
以后就能够设置断点、单步执行、执行表达式、查看做用域变量等,这些功能都是经过 v8 debug protocol 来实现的。
在 vscode 里面写代码,在 chrome devtools 里调试比较麻烦,vscode 也实现了 debugger 的支持,能够直接用 vscode 来调试。
使用vscode 调试能力的方式是修改项目根目录下的 .vscode/launch.json 配置。
点击右下角的按钮来添加一个配置项。这里选择 nodejs 的 attach:
由于已经经过 node --inspect-brk 启动了 websocket 的 debugger server,那么只须要启动 websocket client,而后 attach 上 9229 端口就行。
点击左侧的按钮,就能够连上 debugger server 开始调试:
这样先经过 node --inspect-brk 启动 debugger server,而后再添加 vscode debug 配置来链接上太麻烦了,能不能把这两步合并呢?
固然能够,只要添加一个 launch 的配置:
这里的 type 是 launch,就是启动 debgger server 而且启动一个 debugger client 链接上该 server。运行的程序是根目录下的 index2.js,还能够设置 stopOnEntry 来在首行断住。
点击调试,就能够看到可以成功的调试该 js 文件。
vscode 会启动 debugger server,而后启动 debugger client 自动链接上该 server,这些都不须要咱们去关心。
这样咱们就能够成功的使用 vscode debugger 来调试 nodejs 代码。
debugger client 中咱们最经常使用的仍是 vscode,这里着重讲一下 vscode debugger 的各类场景下的配置。
若是调试 ts 代码,确定不能调试编译后的代码,要可以映射回源码,这个是 sourcemap 作的事情。调试工具都支持 sourcemap,好比 chrome devtools 和 vscode debugger,都支持文件末尾的 sourcemap url 的解析:
//# sourceMappingURL=index.js.map
复制代码
这样当调试 index.js的时候,若是它是 ts 编译的出来的,就会自动找到对应的 ts。
固然,若是调试配置里面直接指定了 ts,那么要可以调试须要再配置 outFiles,告诉 vscode 去哪里找 sourcemap。
这样,在 ts 源码中打的断点和在编译出的 js 打的断点都能生效。
当代码中有子进程的时候,就有了第二条控制流,须要再启动一个 debugger。
好比 vscode,它是基于 electron,须要启动一个主进程,一些渲染进程。主进程是经过 launch 启动的,而渲染进程则是后来 attach 的。
主进程启动的时候,经过 --remote-debugging-port 来指定子进程自动的时候的 debugger server 的端口。
outFiles 来指定 sourcemap 的位置,这样才能够直接调试 ts 源码。runtimeExecutable 是用 vscode 的运行时替代掉了 nodejs(通常不须要设置)。
而后渲染进程是后面启动的,咱们经过参数配置了会启动在 9222 端口,那么只要 attach 到那个端口就能够调试该进程了。
vscode 支持多 target 调试,也就是能够在 vscode 里面同时启动 多个 debugger。能够切换不一样的 debugger 来调试不一样的进程。
debugger 只能打断点么,不是的,它还能够这么用,加日志,不污染源码。
debugger 的使用是一项很重要的能力,对于 nodejs 水平的提高颇有帮助。
nodejs debugger 的原理是 js 引擎会启动 debugger server(websocket),等待客户端链接,咱们能够经过各类 debugger client 连上来进行调试,好比 chrome devtools、vscode debugger。
调试 nodejs 代码更多仍是使用 vscode debugger(固然有的时候也会使用 chrome devtools 调试,基于 chrome devtools 的 memory 来进行内存分析,定位内存泄漏问题的时候颇有帮助)。
vscode debugger 的使用主要是在 .vscode/launch.json 里面添加调试配置。
调试配置分为 launch 和 attach 两种:
具体的配置项经常使用的有:
基于这些配置咱们就能够调试各类场景下的 nodejs 代码,须要编译的,或者多个进程的。
不夸张地说,若是你熟悉了 debugger 的使用,理解各类 nodejs 代码都会简单不少。 但愿这篇文章可以帮助你们了解 debugger 的原理,而且可以使用 chrome devtools 或者 vscode debugger 来调试 nodejs 代码。知道有 sourcemap 以及多进程的状况下都怎么调试。