首页 / Node.js 教程 / 调试技巧

Node.js 教程

调试技巧

本教程共 76 篇 · 第 64 篇 · 更新于 2026-07-25 · 约 7 分钟阅读

Node.js调试inspectDevTools断点

64. 调试技巧

本节目标:- --inspect / --inspect-brk / --inspect-wait 的区别与用法 - 用 Chrome DevTools 连上 Node 进程,设置断点、单步、看变量 - VS Code 的 launch.json 断点调试 - debug 模块做条件式日志 - 异步代码调试的几个要点与安全隐患提醒

console.log 是每个人的第一行调试代码,但面对异步调用栈、内存泄漏、只在特定时序下出现的 race condition,console.log 就显得力不从心了。Node.js 内置了 V8 Inspector 协议,能让你用 Chrome DevTools 或 VS Code 像调试前端一样,打断点、单步执行、实时看变量。这一章把这些调试手段理一遍。

Inspector 是什么

Node.js 内置了一个叫 Inspector 的调试代理(agent)。启动时带上 --inspect,它就在 127.0.0.1:9229 监听一个调试客户端。这个客户端可以是任何实现了 V8 Inspector 协议的工具,最常见的是 Chrome DevTools 和 VS Code。

最基础的启动:

node --inspect app.js

进程照常运行你的代码,同时开放了调试端口。默认绑定 127.0.0.1(本机),不对外暴露,这点很重要,等下讲安全时再说。

几个相关开关,别搞混:

标志行为
--inspect正常启动,同时开调试端口
--inspect-brk在用户代码第一行之前暂停,等你连上再继续
--inspect-wait启动后等待调试器连上才继续执行
--inspect=host:port自定义绑定的地址和端口

--inspect-brk 是我最常用的一招:它让程序「悬」在第一行,你连上去设好断点,再让它在入口处继续。新手最容易犯的错是 --inspect 一启动程序就跑完了,你还没来得及断点,进程已经退出了。-brk 完美避开这个坑。

Tip

想在已经运行的进程上开调试?给进程发 SIGUSR1 信号(Linux/macOS):kill -SIGUSR1 <pid>。它会当场激活 Inspector。注意 Windows 不支持这个信号。

用 Chrome DevTools 调试

步骤很简单:

  1. 终端跑 node --inspect-brk app.js,你会看到一行提示,说 Inspector 监听在 ws://127.0.0.1:9229/...
  2. 打开 Chrome 浏览器,地址栏输入 chrome://inspect
  3. 点「Configure」确认目标 host:port 在列表里,稍等片刻,你的 Node 进程会出现在 Remote Target 列表。
  4. 点进程下方的「inspect」,弹出 DevTools 窗口,停在入口处。

连上之后,Sources 面板就是主战场:

  • 断点:在代码行号左边点一下,运行到那行就停。
  • 单步:Step Over 跨过、Step Into 进函数、Step Out 跳出。
  • Scope:暂停时看当前作用域里的局部变量、全局变量,实时值一目了然。
  • Call Stack:当前调用栈,包括异步调用链(开启 Async 后能看到 await 的前世今生)。
  • Console:在暂停点直接敲表达式求值,比如 user.nameJSON.stringify(data)
Note

勾上暂停按钮旁边那个「Pause on caught exceptions」(带波浪线的圆圈),程序一抛错就自动停,省得你手动在出错位置找断点。排查偶发异常特别好用。

在 VS Code 里断点调试

VS Code 对 Node 调试是一等公民,体验比切到浏览器顺手。核心是一个 .vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "启动程序",
      "program": "${workspaceFolder}/app.js",
      "skipFiles": ["<node_internals>/**"]
    },
    {
      "type": "node",
      "request": "attach",
      "name": "附加到进程",
      "port": 9229
    }
  ]
}

launch 是「启动并调试」:点运行按钮,VS Code 自己带 --inspect 起进程,断点直接生效。attach 是「你已经用 node --inspect 起了进程,VS Code 再连上去」,适合调试已经在跑的服务。

VS Code 还有几个杀手锏:

  • 条件断点:右键断点,设个条件,比如 userId === 3,只有满足时才停,避免在循环里每次都断。
  • Logpoints:右键断点选「转为 Logpoint」,填一段表达式,命中时往控制台打印,但不改代码、不暂停。相当于临时 console.log 又不留痕。
  • Watch:把 user.agecache.size 这类表达式加进 Watch 面板,单步时实时看它们变化。
Tip

嫌配 launch.json 麻烦?VS Code 有个「JavaScript Debug Terminal」:开一个这种终端,在里面 node app.js 跑起来,它会自动附加调试器,断点直接生效,连配置都不用写。

debug 模块:更聪明的日志

console.log 满天飞的问题在于:上线时你得一个个删,或者它们一直刷屏。Node 生态里有个老牌的 debug 模块,让你按「命名空间」开关节志:

npm install debug
import debug from 'debug';

const logServer = debug('app:server');
const logDb = debug('app:database');

logServer('服务启动在 %d 端口', 3000);
logDb('连上数据库 %s', 'mongodb://localhost');

默认这些日志不输出。想看哪个,用环境变量打开:

# 只看 server 和 auth 两个命名空间
DEBUG=app:server,app:auth node app.js

# 看 app: 下所有
DEBUG=app:* node app.js

# 全开但排除 database
DEBUG=app:*,-app:database node app.js

每个命名空间有独立颜色,还带时间戳和间隔毫秒数。比满屏 console.log 清爽太多,而且生产环境不设这个变量就零开销。

Warning

debug 输出里可能带敏感信息(用户 ID、token 片段)。生产环境除非排查问题,否则别开着 DEBUG=* 全量打印,日志里泄密比你想的常见。

异步代码调试要点

Node.js 的异步是调试里最容易晕的部分。几个实用建议:

  • async/await 代替深层 .then 嵌套,调用栈是线性的,断点也好打。
  • 在 DevTools / VS Code 里开启「Async stack traces」,能看清一个 await 是从哪条异步链路过来的,不再是孤零零的一帧。
  • 顶层一定要监听 unhandledRejectionuncaughtException,否则 Promise 悄悄 reject 了你根本不知道:
process.on('unhandledRejection', (reason) => {
  console.error('未处理的 Promise 拒绝:', reason);
});
  • 跨异步边界追踪时,给请求加个 correlation id(关联 ID),日志里串起同一次请求的所有步骤。

安全:别把调试端口暴露出去

最后这点很多教程不提,但很关键。Inspector 对进程有完全控制权——连上的人能执行任意代码。所以:

  • 默认 --inspect 只绑 127.0.0.1,本机外连不上,这是安全的。
  • 千万别把它绑到 0.0.0.0 或公网 IP,否则任何人都能连进来跑代码,等于把服务器大门敞开。
  • 需要远程调试时,正确做法是走 SSH 隧道:远端照常 node --inspect app.js(只绑本机),本地用 ssh -L 9221:localhost:9229 user@remote 把远端 9229 映射到本地 9221,然后本地 DevTools 连 localhost:9221。这样流量走加密隧道,不直接暴露端口。
Note

即便绑在 127.0.0.1,本机其他程序也能连上 Inspector,这是设计如此(方便本地调试器接入)。所以调试端口不要和不可信的本地程序共处同一台机器跑敏感服务。

排查套路小结

遇到诡异 bug,我的常规顺序是:先 --inspect-brk 起进程,在可疑函数前设断点,单步看变量;异步问题开 Async 栈、加 correlation id;日志太多就换 debug 模块按命名空间开关。真到了内存或 CPU 层面,再上 --prof 和堆快照(这部分放性能与诊断相关章节细讲)。工具到位了,调试从「玄学」变成「按图索骥」。