Node.js 深度调试指南

在 Node.js 项目开发过程当中,随着项目的发展,调用关系愈来愈复杂,调试工具的重要性日益凸显。php

Node(v6.3+)集成了方便好用 V8 Inspect 调试器,容许咱们经过 Chrome DevTools 进行图形化的调试和性能分析。同时,咱们也可使用 VS Code,Webstorm 等支持的编辑器对 Node.js 程序进行调试。html

Node Inspect

要想启动调试器,咱们须要在启动 Node.js 应用程序时传入 --inspect 标志,也可使用该标志提供自定义的端口,例如 --inspect=9222 将会在 9222 端口上接受开发者工具的链接。前端

一段简单的代码node

 function log() {
   let a = 1;
   console.log(a);
   a = 2;
   console.log(a);
 }
 ​
 log();

 



使用 node --inspect 启动web

img

这时咱们会发现,程序直接执行完成了,没有中断,致使咱们没法使用 Chrome DevTools 进行调试。对于这种直接执行的代码,咱们可使用 --inspect-brk 参数,在应用程序代码的第一行终端,而后再进行调试。chrome

img

Chrome DevTools

当开启 Node 调试后,咱们能够打开 Chrome,访问 chrome://inspect ,在 Devices 中查找到咱们的 Node.js 程序,点击 inspect 打开调试面板进行操做npm

img

在调试工具窗口,咱们能够设置断点,运行程序进行调试json

img

运行中程序调试

在某些状况下,咱们能够须要对正在运行的 Node.js 程序进行调试,好比 Express Web 服务。咱们不可能中止服务,再以 --inspect 运行调试。浏览器

对于这种状况,咱们能够先获取服务的进程 Id服务器

img

向脚本进程发送 SIGUSR1 信号,就能够创建调试链接

 kill -SIGUSR1 34943
 复制代码

img

在 Windows 平台下,可使用下面的命令

 node -e 'process._debugProcess(30464)'

 



须要注意的是:这种调试任然会中断服务进程的执行。

VS Code 调试

快速调试

对于简单的应用程序,能够打开文件,按 F5 并选择调试类型为 Node,便可进行调试

img

使用配置调试

对于大多数的调试场景,更推荐使用配置文件,由于它能够配置并保存调试设置的信息,方便咱们下次快速使用。在 VC Code 中,调试配置一般存储在 .vscode 文件夹下的 launch.json 文件中 。能够点击左侧栏目中的调试图标,快速建立 launch.json 文件

img

VS Code 会自动下面相似的 launch.json 调试配置文件,其中 program 表明咱们须要调试的文件路径,workspaceFolder 为当前工做区的路径,一般是项目的根目录

 {
   "version": "0.2.0",
   "configurations": [
     {
       "type": "node",
       "request": "launch",
       "name": "启动程序",
       "skipFiles": ["<node_internals>/**"],
       "program": "${workspaceFolder}/index.js"
     }
   ]
 }

 



设置断点,便可启动调试,并在左侧的树视图中看到变量对应的值以及堆栈信息

img

launch.json

launch.json 中有许多不一样的属性,支持不一样的调试器和调试场景,下面的属性在每一个启动配置中是必须的

  • name - 当前调试配置项的名称,可读性要好,区分每一个调试配置项

  • type - 用于此启动配置的调试器的类型。每一个已安装的调试扩展都引入一种类型:例如node,php,go 等。

  • request - 当前调试项的类型,目前支持 launch 和 attach 两种类型。launch 适合调试未启动的程序,attach 则适合调试已经运行的程序。

一些其余比较有用的选项:

  • program - 启动调试器时要运行的可执行程序或文件

  • args - 传递给程序进行调试的参数

  • env - 调试时的环境变量

  • envFile - 包含环境变量键值对的文件

  • stopOnEntry - 程序启动时当即中断

  • port - 链接到正在运行的调试器的端口

  • runtimeExecutable - 启用调试的可执行 Runtime,默认是 Node

日志点 - Logpoints

VS Code 提供了好用的调试小工具 - 日志点,日志点是断点的一种变体,它不 "中断 "进入调试器,而是将一条消息记录到控制台,日志点对于在调试不能暂停或中止的生产服务器时注入日志特别有用。

img

NPM 脚本调试

除了使用 node 启动 Node.js 项目以外,VS Code 还支持自定义启动程序 runtime,借助这个能力,能够直接使用 NPM 启动调试。以下面,使用 npm run debug 启动调试

 "scripts": {
     "debug": "node --inspect server.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 文件

img

远程调试

当咱们须要在真实的服务器等远程运行环境调试 Node.js 时,咱们能够利用上面提到的方式,在服务器上开启 Node.js 调试功能,并在本地链接上远程的调试端口进行调试。

VS Code 默认支持远程调试,咱们须要 launch.json 配置文件中指定远程服务的 IP 地址以及端口,以下所示:

 {
   "type": "node",
   "request": "attach",
   "name": "远程调试",
   "address": "IP 地址",
   "port": "9229"
 }

 



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 选项致使的。

img

这里咱们在启动进程时添加上 --inspect 参数,同时注意要指定一个默认 9229 端口以外的端口号,避免调试端口冲突

 - const sp = spawn("node", ["./fork_server.js"]);
 + const sp = spawn("node", ["--inspect=9230", "./fork_server.js"]);

 



再次启动,就能看到两个调试信息输出了

img

固然,怎么能少得了强大的 VS Code 呢。VS Code 的 Node 调试器提供了一种机制,能够追踪全部子进程,并在调试模式下,自动连接进程。能够经过 autoAttachChildProcesses 属性开启此机制:

 {
   "type": "node",
   "request": "launch",
   "name": "启动程序",
   "program": "${workspaceFolder}/fork.js",
   "autoAttachChildProcesses": true
 }

 



启动后,便可对父进程,或子进程进行断点调试,效果以下

img

结语

你们有什么要说的,欢迎在评论区留言

对了,小编为你们准备了一套2020最新的web前端资料,须要点击下方连接获取方式

一、点赞+评论(勾选“同时转发”)

学习前端,你掌握这些。二线也能轻松拿8K以上

参考文献

Debugging - Getting Started | Node.js

Debug Node.js Apps using Visual Studio Code

相关文章
相关标签/搜索