Node.js 深度调试方法解析
2020年07月28日
作者:前端-发际线还在原文
在 Node.js 项目开发过程中,随着项目的发展,调用关系越来越复杂,调试工具的重要性日益凸显。
Node(v6.3+)集成了方便好用 V8 Inspect 调试器,允许我们通过 Chrome DevTools 进行图形化的调试和性能分析。同时,我们也可以使用 VS Code,Webstorm 等支持的编辑器对 Node.js 程序进行调试。
Node Inspect
要想启动调试器,我们需要在启动 Node.js 应用程序时传入 --inspect 标志,也可以使用该标志提供自定义的端口,例如 --inspect=9222 将会在 9222 端口上接受开发者工具的连接。
一段简单的代码
function log() {
let a = 1;
console.log(a);
a = 2;
console.log(a);
}
log();
使用 node --inspect 启动
Chrome DevTools
当开启 Node 调试后,我们可以打开 Chrome,访问 chrome://inspect ,在 Devices 中查找到我们的 Node.js 程序,点击 inspect 打开调试面板进行操作
运行中程序调试
在某些情况下,我们可以需要对正在运行的 Node.js 程序进行调试,比如 Express Web 服务。我们不可能停止服务,再以 --inspect 运行调试。
对于这种情况,我们可以先获取服务的进程 Id
复制代码
需要注意的是:这种调试任然会中断服务进程的执行。
VS Code 调试
快速调试
对于简单的应用程序,可以打开文件,按 F5 并选择调试类型为 Node,即可进行调试
VS Code 会自动下面类似的 launch.json 调试配置文件,其中 program 代表我们需要调试的文件路径,workspaceFolder 为当前工作区的路径,通常是项目的根目录
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/index.js"
}
]
}
设置断点,即可启动调试,并在左侧的树视图中看到变量对应的值以及堆栈信息
NPM 脚本调试
除了使用 node 启动 Node.js 项目之外,VS Code 还支持自定义启动程序 runtime,借助这个能力,可以直接使用 NPM 启动调试。如下面,使用 npm run debug 启动调试
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/index.js"
}
]
}
launch.json
{
"type": "node",
"request": "launch",
"name": "NPM 启动",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "debug"],
"port": 9229
}
TypeScript 调试
VS Code 内置的 Node.js 的调试器支持 JavaScript Source Map,可以结合 Source Map 调试转译前的代码,如 TypeScript,压缩混淆的 JavaScript 代码等都可以利用 Source Map 的支持调试源码。
我准备了一个简单的 TS Server Demo,可以直接 Clone 源码本地测试。下面是项目中的 src/index.ts 文件,创建了一个 HTTP Server
import * as http from "http";
let reqCount = 1;
http
.createServer((req, res) => {
const message = `Request Count: ${reqCount}`;
res.writeHead(200, { "Content-Type": "text/html" });
res.end(`<html><div>${message}</div></html>`);
console.log("handled request: " + reqCount++);
})
.listen(3000);
console.log("server running on port 3000");
创建 tsconfig.json 配置,配置编译生成 Source Map
{
"compilerOptions": {
"outDir": "./dist",
"sourceMap": true
},
"include": ["src/**/*"]
}
使用 tsc 编译一下,生成 JS 代码:dist/index.js,创建调试配置,入口文件为 dist/index.js
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/dist/index.js",
"skipFiles": ["<node_internals>/**"]
}
然后打断点,启动调试,浏览器访问 http://localhost:3000,即可看到调试进入了 TS 文件
VS Code 会自动加载远程的文件,展示为只读代码供调试使用。
如果想要在调试的过程中编辑源代码,或者更好的调试体验,可以在远程文件夹和本地项目之间设置一个映射。VS Code 提供了 localRoot 和 remoteRoot 属性来映射本地 VS Code 项目和(远程)Node.js 文件夹:
{
"type": "node",
"request": "attach",
"name": "远程调试",
"address": "IP 地址",
"port": "9229",
"localRoot": "${workspaceFolder}/src",
"remoteRoot": "/var/user/"
}
在建立映射关系后,即可在本地项目进行断点调试,远程的断点信息会同步到本地项目,使用起来十分方便。
子进程调试
与普通进程调试原理一致,子进程调试时也需要传入 --inspect 参数,这一点需要特别注意,否则无法启动子进程调试。
如下通过子进程启动 Server 的例子:
// fork.js 文件
const { spawn } = require("child_process");
const sp = spawn("node", ["./fork_server.js"]);
console.log("父进程 PID", sp.pid);
sp.stdout.on("data", (data) => {
console.log(`stdout: ${data}`);
});
sp.stderr.on("data", (data) => {
console.error(`stderr: ${data}`);
});
如果直接使用 node --inspect 启动主进程的话,会发现只显示了主进程的调试端口,这就是因为我们在程序中启动子进程时没有传递 --inspect 选项导致的。
当然,怎么能少得了强大的 VS Code 呢。VS Code 的 Node 调试器提供了一种机制,可以追踪所有子进程,并在调试模式下,自动链接进程。可以通过 autoAttachChildProcesses 属性开启此机制:
{
"type": "node",
"request": "launch",
"name": "启动程序",
"program": "${workspaceFolder}/fork.js",
"autoAttachChildProcesses": true
}
启动后,即可对父进程,或子进程进行断点调试,效果如下
结语
到此这篇关于Node.js 深度调试方法解析的文章就介绍到这了,更多相关Node.js 深度调方法内容请搜索来客网以前的文章或继续浏览下面的相关文章希望大家以后多多支持来客网!