人人都会AI编程

2.4 常用调试方式:终端调试、Chrome DevTools、VS Code 断点调试

更新时间:2026-07-11

即使编写了很严谨的代码,出现 Bug 也是不可避免的。Node.js 提供了多种调试手段,让开发者能够直观地观察程序运行过程中的变量值、调用栈和执行流程。本节聚焦三种最高效的调试方式,从简单的终端打印到强大的图形化调试器,帮助你在日常开发中快速定位问题。

2.4.1 终端调试:console + 内置调试器

console 的更多玩法

初学者最常用的调试方式是在代码中加 console.log。这确实简单有效,但 Node.js 的 console 对象远不止 log 一种能力:

  • console.dir(obj, { depth: null }) — 完整展开对象结构,比 log 更适合查看深层嵌套对象。
  • console.table(array) — 将数组或对象以表格形式展示,特别适合查看数据库查询结果或列表数据。
  • console.time('label') / console.timeEnd('label') — 精确测量一段代码的执行耗时,常用于性能排查。
  • console.trace() — 打印当前的调用栈路径,帮助你回答“这段代码是从哪里被调用的”。
  • console.assert(condition, message) — 当条件为 false 时输出错误信息,作为轻量级的运行时检查。

例如,排查某接口耗时过长:

async function getUserData(userId) {
  console.time('getUserData');
  const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
  const orders = await db.query('SELECT * FROM orders WHERE user_id = ?', [userId]);
  console.timeEnd('getUserData'); // 输出类似:getUserData: 245ms
  return { user, orders };
}

在生产环境中不建议保留过多的 console.log,因为它们会影响性能并暴露敏感信息。适时使用 debug 模块(一个基于环境变量控制输出的轻量库)可以更优雅地管理日志输出级别。

Node.js 内置命令行调试器

console.log 满足不了需求时,Node.js 自带的命令行调试器可以让你在终端中逐步执行代码。启用方式:

node inspect your-script.js

这会启动一个调试会话,程序会在第一行代码前暂停,进入交互模式。在此模式下,你可以使用下列命令:

  • ccont — 继续执行直到下一个断点或程序结束。
  • nnext — 单步执行(下一步),如果是函数调用则不会进入函数内部。
  • sstep — 步入函数调用内部。
  • oout — 执行完当前函数并返回到调用处。
  • setBreakpoint()sb() — 在当前行设置断点(需要在代码中先进入调试器)。
  • repl — 在当前暂停的上下文中打开一个 REPL,可以直接访问变量和表达式。
  • watch(expr) — 添加一个监视表达式,每次暂停时自动输出值。

虽然内置调试器在纯终端环境中(如远程服务器)非常有用,但对于日常开发,图形化的调试方式会更直观高效。下面我们介绍两种主流方案。

2.4.2 Chrome DevTools 调试 Node.js

基于 V8 引擎的 Node.js 天然与 Chrome 的开发者工具兼容。2016 年起,Node.js 支持通过 Chrome DevTools 协议进行远程调试,开发者可以在熟悉的浏览器界面中调试服务端代码。

启动调试

在启动脚本时添加 --inspect 参数:

node --inspect your-script.js

如果想在代码开头就暂停(即断点在第一行),使用 --inspect-brk

node --inspect-brk your-script.js

启动后会看到类似输出:

Debugger listening on ws://127.0.0.1:9229/abc123de-4567-...

连接 Chrome

  1. 打开 Chrome 浏览器,在地址栏输入 chrome://inspect 并回车。
  2. Remote Target 列表中会看到正在运行的 Node.js 进程,点击对应的 inspect 链接。
  3. 弹出独立的 DevTools 窗口,其界面与调试前端 JavaScript 时几乎完全一致。

核心调试功能

  • Source 面板:左侧文件树可以选择要调试的脚本,点击行号可以设置/移除断点。
  • 断点类型:除了普通代码行断点,还可以添加条件断点(右键行号 → “Add conditional breakpoint”)、XHR/fetch 断点、事件监听断点等。
  • Call Stack:右侧显示当前调用栈,点击任意栈帧可跳转到对应代码并查看该上下文的变量。
  • Scope 与 Watch:查看当前作用域下的局部变量、闭包变量和全局变量,也可以手动添加监视表达式。
  • Console:在断点暂停状态下,控制台可以直接访问当前上下文变量,执行任意表达式,方便实验和排查。
  • Network:调试 HTTP 请求时,可以查看请求的 Header、Body 和响应,与前端调试无异。

实际使用案例

假设我们有一个 Express 服务的中间件出现问题:

app.use((req, res, next) => {
  const token = req.headers.authorization;
  // 断点打在这行,想看清楚 token 到底是 undefined 还是格式错误
  const decoded = jwt.verify(token, secret);
  req.user = decoded;
  next();
});

启动命令 node --inspect-brk server.js,然后连接 DevTools,在该行设置断点。当请求到来时执行暂停,我们可以在 Scope 面板中看到 req.headers 的全部内容,在 Console 中输入 token 直接查看值,或者调用其他函数尝试解析。这种可视化的变量探查能力比单纯打印日志要强大得多。

远程调试

如果代码运行在远程服务器或 Docker 容器中,可以通过 SSH 端口转发将远程调试端口映射到本地:

ssh -L 9229:localhost:9229 user@your-server

然后在本地的 Chrome 中就能连接到远程 Node.js 进程。注意生产环境中切勿开启调试端口,以免暴露敏感信息。

2.4.3 VS Code 断点调试

对于日常开发,最顺手的调试方式无疑是集成在代码编辑器内部。VS Code 对 Node.js 调试的支持非常完善,全部体验无需离开编辑窗口。

快速启动:Auto Attach

VS Code 提供了一种“自动附加”模式,会在你启动 Node.js 脚本时自动连接调试器。开启方法:

  1. 打开命令面板 (Cmd+Shift+P / Ctrl+Shift+P),输入 Debug: Toggle Auto Attach
  2. 选择 AlwaysOnly with flag
  3. 然后在集成终端中运行任何 Node 脚本,调试器会自动连接并在代码断点处暂停。

手动配置:launch.json

如果需要更精细的控制(如传递环境变量、参数),可以创建调试配置。

在 VS Code 左侧点击“运行和调试”图标(或按 Ctrl+Shift+D),点击“创建 launch.json 文件”,选择 Node.js 环境。一个典型的配置如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "调试 server.js",
      "program": "${workspaceFolder}/server.js",
      "args": ["--port", "3000"],
      "env": { "NODE_ENV": "development" },
      "skipFiles": ["<node_internals>/**", "node_modules/**"],
      "console": "integratedTerminal"
    },
    {
      "type": "node",
      "request": "attach",
      "name": "附加到进程",
      "processId": "${command:PickProcess}"
    }
  ]
}
  • launch 模式:直接从 VS Code 启动你的程序,适合开发调试。
  • attach 模式:附加到一个已在运行的 Node.js 进程(例如通过 node --inspect 启动的程序),适合调试生产问题或已启动的服务。
  • skipFiles 可以忽略 node 内部代码和 node_modules 中的文件,避免调试时跳入第三方库源码。

配置完成后,选择相应的配置名称,按 F5 即可开始调试。

强大的断点功能

VS Code 支持多种断点类型:

  • 普通断点:点击行号左侧。
  • 条件断点:右键 → 添加“条件断点”,输入条件表达式(如 user.id === 123),只有当条件为真时才会暂停。
  • 日志点(Logpoint):右键 → 添加“日志点”,输入一个表达式,程序运行到这里不会暂停,而是将表达式的值输出到调试控制台。这相当于非侵入式的 console.log,不需要修改代码。
  • 内联断点:在一行代码内部的某个表达式上设置断点,只有执行到该表达式时才暂停。

调试时右侧面板提供变量、监视、调用堆栈、断点列表和调试控制台。你可以在暂停状态下自由使用调试控制台执行任何 JavaScript 表达式,甚至可以重新赋值来模拟特定状态。

实际调试场景

我们调试一个异步函数:

async function processOrders(orders) {
  const results = [];
  for (const order of orders) {
    const processed = await heavyProcessing(order); // 在这行设置条件断点: order.amount > 1000
    results.push(processed);
  }
  return results;
}

启动调试后,每次只有金额大于 1000 的订单才会触发暂停,我们可以单步跟踪 heavyProcessing 内部的执行路径。在单步过程中,变量视图会实时更新 order 的值,调用栈清晰展示从请求处理器一直到这里的所有函数调用。

配合 Nodemon 实现热重载调试

开发时通常使用 nodemon 自动重启服务。VS Code 可以很方便地与 nodemon 结合:

launch.json 中将 runtimeExecutable 设置为 nodemon 的路径,或者使用 "runtimeArgs": ["--watch", "--inspect"] 启动 nodemon。这样每次保存文件服务自动重启,调试器会断开旧进程并连接新进程,无需手动操作。

{
  "type": "node",
  "request": "launch",
  "name": "Nodemon 调试",
  "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/nodemon",
  "program": "${workspaceFolder}/server.js",
  "restart": true,
  "console": "integratedTerminal",
  "internalConsoleOptions": "neverOpen"
}

2.4.4 三种方式的选择建议

  • 快速排错或观察变量:用 console.log / console.dir 可以马上获取信息,但不适合复杂流程。
  • 远程服务器无图形界面:使用内置的 node inspect 命令行调试器,或者开启 --inspect 并用 SSH 转发后通过 Chrome DevTools 连接。
  • 日常开发:强烈推荐使用 VS Code 断点调试,它将编码、运行、断点检查融为一体,条件断点和日志点功能尤其方便,能大幅提升调试效率。

无论采用哪种方式,掌握调试工具都会让你对代码的执行流程了如指掌,而不必在脑子里推演异步操作的执行顺序。在后续章节中,当我们深入事件循环和流(Stream)原理时,这些调试手段将成为你验证理解和排查问题的利器。