很长一段时间,调试 Nodejs 代码都是通过在代码里写 console.log() 进行的。在 infoq 上看到一篇文章,是说十倍效率工程师有哪些特质,其中一点就是擅长调试与测试。这给了我很大动力去弄明白这些之前模糊的概念。
调试服务端
创建 index.js,在服务端想要运行该文件,需要在终端输入 $ node index.js。
node 程序
会读取 index.js 源码,如果 index.js 中引用了其它 js 文件,依次读取源码,最后执行。
(安装的 Nodejs 软件里包含很多个子程序,node 是其中一个程序,用于执行 js 文件)
在调试 Nodejs 代码时,我们希望代码能一行行执行,而不是像 node 程序那样将整个源码都跑完,这时候需要用 Nodejs 内置的 调试器程序
去运行 index.js。
总结下目前了解的概念:
- 安装的 Nodejs 软件包会包含很多子程序,比如 node 程序和调试器程序;
- node 程序的特点是一下子将整个代码都跑完;
- 调试器程序的特点是一行行执行代码;
调试器程序执行 js 文件后,会启一个 websocket 的服务,调试器程序作为服务端,只提供与调试相关的底层功能,这样做的好处是开发人员可以自由选择调试客户端:你可以选择在终端中调试,也可以选择在谷歌浏览器中调试,甚至可以在 Vscode 中调试,只要你的调试客户端连接到调试服务端即可。
创建 index.js 文件作为调试演示代码,内容如下:
const add = require('./add')
const a = 1
const b = 2
debugger
console.log(add(a, b))
下面分别介绍用不同的调试器客户端进行调试。
终端中调试
Nodejs 也自带了一个调试器客户端,在终端中进行调试。
$ node inspect index.js
node inspect
表示启动调试器服务端,并在终端打开调试器客户端。
$ node inspect index.js
< Debugger listening on ws://127.0.0.1:9229/858f5307-2af1-472a-bd73-a2fbe5b8578b
< For help, see: https://nodejs.org/en/docs/inspector
< Debugger attached.
Break on start in index.js:1
> 1 const add = require('./add')
2
3 const a = 1
debug>
第一行 Debugger listening on ws://127.0.0.1:9229/
,表示调试服务端已经启动了,并且监听着 9229 这个端口。
第三行 Debugger attached
,表示调试器客户端已经连接到调试器服务端了。
输入 help 可以查看调试器有哪些用法。
debug> help
run, restart, r Run the application or reconnect
kill Kill a running application or disconnect
cont, c Resume execution
next, n Continue to next line in current file
step, s Step into, potentially entering a function
out, o Step out, leaving the current function
backtrace, bt Print the current backtrace
list Print the source around the current line where execution
is currently paused
setBreakpoint, sb Set a breakpoint
clearBreakpoint, cb Clear a breakpoint
......
debug>
输入 n,执行下一行代码。
debug> n
break in index.js:3
1 const add = require('./add')
2
> 3 const a = 1
4 const b = 2
5
输入 c,跳转到下一个断点处。
debug> c
break in index.js:6
4 const b = 2
5
> 6 debugger
7 console.log(add(a, b))
8
还有一些常用的命令,在 help 中可以查看详细用法,这里简要列举下,就不一一介绍了。
- restart 重启调试器
- run 开始调试
- kill 停止调试
- s 单步跳进
- o 单步跳出
Chrome Devtool 中调试
谷歌浏览器的开发者工具也可以作为调试客户端调试 Nodejs 代码,只要连接到调试器服务端即可。
$ node --inspect-brk index.js
Debugger listening on ws://127.0.0.1:9229/7513b18d-7a62-44c7-a963-84a90eb826a9
For help, see: https://nodejs.org/en/docs/inspector
node --inspect-brk
表示只启动了调试器服务端,监听端口 9229。此时还没有任何调试器客户端连接哦~~
打开谷歌浏览器的开发者工具,左上角可以看到 nodejs 的 logo,点它。
点击之后弹出的新窗口就是Chrome Devtools 中调试 Nodejs 代码的调试客户端。
- 红字1:窗体标题表示这是 Nodejs 的调试客户端;
- 红字2(Console):服务端打印的日志(console.log)也会在这里打印;
- 红字3(Sources):服务端源代码,调试器并不会见所有服务端代码都推送到这里,只会推送用到的代码;
- 红字4:源码文件,可以点击想要打断点的文件,在右侧打断点调试;
- 红字5(Scope):变量的具体值在这里可以找到。
此时回到终端,可以看到多打印一条消息,最后一行表示调试器客户端连接到调试器服务端了。
$ node --inspect-brk index.js
Debugger listening on ws://127.0.0.1:9229/0a233e15-573b-40a0-956f-76c8e074b5a1
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached. <=============
为什么打开谷歌浏览器的 Chrome Devtools,会自动连接调试器服务端呢?
调试器服务端默认启动端口是 9229,而 Chrome Devtools 默认也会连接 9229 端口。
重新启动调试器服务端,并且指定一个不一样的端口,此时调试器服务端端口变成了 9222。
$ node --inspect-brk=9222 index.js
Debugger listening on ws://127.0.0.1:9222/967b99ee-b726-4c2b-ba08-dec16f1a531a
For help, see: https://nodejs.org/en/docs/inspector
再次打开浏览器,可以看到 Nodejs 的 logo 变成灰色了,也不会主动连接到调试器服务端了。此时需要我们手动设置下 Chrome Devtools 去连接哪个端口。
点击 Nodejs 的 logo 图像,在弹出的窗体中选择 Connection(红字1),点击 Add connection(红字2),在上方的输入框输入要监听的端口号保存即可。
Vscode 中调试
大多数开发者调试代码都会选择 IDE(开发工具) 进行调试,这里以 Vscode 为例进行说明。
用 Vscode 打开 index.js 所在的目录。
这里主要介绍下红字 3 的几个属性的含义:
- type: "node",表示调试 Nodejs 代码,如果调试 PHP 代码,这里写成 type: php;
- request: "launch",launch 表示由
调试器程序
执行 index.js,而不是由node程序
执行 index.js,参考第一点调试器服务端。request 还有一个值 attach,下文再介绍; - name: "Launch Program",红字2左边有个下拉框,name 属性的值即为下拉框中的值;
- program: "${workspaceFolder}/index.js",启动哪个文件,这里表示启动根目录下的 index.js 文件。
- 红字1(调试控制台):可以看到启动了调试器服务端,监听端口 26199,每次调试端口都不一样。Debugger attached 表示调试客户端也连接上服务端了;
- 红字2:调试的相关操作都在这里;
- 红字3:调试过程中变量和表达式的值可以在这里查看。