CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Node.js 运行时进阶/课时/回调与错误栈
RawBlame
课时目录12 节

Node.js 运行时进阶

  1. 01运行时进阶概览
  2. 02定时器与 nextTick
  3. 03回调与错误栈
  4. 04子进程
  5. 05Worker Threads
  6. 06Cluster 与多进程
  7. 07垃圾回收
  8. 08调试 Node
  9. 09APM 与生产监控
  10. 10CLI 工具链
  11. 11global 与内置模块
  12. 12综合练习

回调与错误栈

callbacks、callstack、异步错误。

25 分钟

回调与错误栈

nodejs-essentials 已学 Promise 与 async/await,但 Node 底层与许多老库仍用 callback(err, result) 约定。本课讲 call stack、异步错误传播、stack trace 丢失——写可靠回调和迁移到 Promise 的基础。

学习目标

  • 理解 Node 错误优先回调约定 (err, data) => {}
  • 区分同步 throw 与异步 callback(err) 的行为差异
  • 用 util.promisify、async_hooks 改善错误栈可读性

错误优先回调

Node 核心 API(fs 老接口、部分 stream)约定:第一个参数是 Error 或 null。

import fs from "node:fs";

fs.readFile("missing.txt", "utf8", (err, data) => {
  if (err) {
    console.error("read failed:", err.message);
    return;
  }
  console.log(data.length);
});

规则:成功时 err === null;失败时 err 为 Error 实例,不要再读 data。

Call Stack 与异步断档

同步代码 throw 时,stack 从 throw 点到 catch 连续。异步 callback 里 throw 若没有域或 try/catch,会变成 uncaughtException 并可能崩溃进程:

setTimeout(() => {
  throw new Error("async boom"); // 不在外层 try/catch 范围内
}, 0);

try { setTimeout(...) } catch 捕不到 定时器内的 throw——回调在另一轮 Event Loop 执行。

最佳实践(衔接 nva-errors):

  • callback 风格:if (err) return cb(err)
  • Promise:main().catch(err => { ...; process.exitCode = 1 })
  • EventEmitter:监听 error 事件,否则 unhandled 会 crash

回调地狱与 promisify

import { promisify } from "node:util";
import fs from "node:fs";

const readFile = promisify(fs.readFile);

async function loadConfig(path) {
  const text = await readFile(path, "utf8");
  return JSON.parse(text);
}

promisify 要求 callback 遵循 (err, result);多结果 API 需自定义 wrapper。

异步错误栈:cause 与 async_hooks

Node 16+ Error 支持 cause 链:

try {
  await readFile("x.txt");
} catch (err) {
  throw new Error("load config failed", { cause: err });
}

调试深层 async 链时,开启 --async-stack-traces(V8 默认在许多版本已改善)或在测试里断言 err.cause。

生产环境避免把完整 stack 返回给客户端;日志里保留 stack(见 nrt-apm)。

与 Java 异常对照

Node callback / PromiseJava
错误类型多为 Error 对象,非类型化checked / unchecked
异步必须显式传 err 或 rejectCompletableFuture
未捕获uncaughtException / unhandledRejectionThread uncaught handler

练习

  • 写 callback 版 readJson(path, cb),错误时传 SyntaxError 或 ENOENT
  • 同一逻辑用 promisify + async/await 重写
  • 故意在 setTimeout 内 throw,观察进程行为与 --unhandled-rejections=strict 差异

小结

回调要 err-first;异步 throw 不会被外层同步 catch 接住。 下一课子进程——把任务挪到独立进程隔离崩溃与 CPU。

加载本节练习…
← 上一课定时器与 nextTick下一课 →子进程