核心对策是通过主动包裹、静态检查与全局兜底三层防线防控未处理 promise 错误:每个 await 单独 try-catch;用 eslint/ts 提前拦截浮游 promise;监听 unhandledrejection 并上报;并行任务优先用 promise.allsettled。

核心对策是:不让错误有“漏网之机”——通过主动包裹 + 静态检查 + 全局兜底三层防线,把“忘记写 try-catch”带来的风险降到最低。
每个 await 表达式单独用 try-catch 包裹
async 函数内部的错误不会自动向上冒泡,只对当前 await 生效。不能靠外层一个 try 包整个函数体来覆盖所有可能失败点。
- 对真正可能出错的操作单独处理,比如
await fetch()、await response.json()、await fs.readFile() - 避免把无关逻辑(如日志、变量赋值)也塞进 try 块里,否则难以定位具体哪一步失败
- catch 中至少记录
err.message和err.stack,必要时补充上下文(如请求 URL、用户 ID)
用 ESLint 或 TypeScript 提前拦截“发射即忘”
工具能发现那些被调用却未 await、也未 .catch() 的 Promise,这是最常被忽略的崩溃源头。
- 启用 ESLint 规则:
require-await(强制 async 函数中使用 await)、no-floating-promises(禁止未处理的 Promise) - TypeScript 编译选项开启
"noImplicitReturns": true和"strict": true,配合类型推导识别未处理 rejection - CI 流程中加入 lint 检查,不通过则阻断合并
全局监听 unhandledRejection 作为最后防线
Node.js v15+ 默认将未处理的 Promise rejection 视为致命错误,进程会直接退出。必须注册监听防止静默崩溃。
- 在应用启动最早期注册一次:
process.on('unhandledRejection', (reason, promise) => { /* 上报 + 记录 + 可选退出 */ }) - 不要只
console.error,生产环境应把reason发送到监控系统(如 Sentry),带上进程 ID、时间戳、堆栈等上下文 - 监听后可选择
process.exit(1)主动终止,避免僵尸进程;但需确保已释放关键资源(如 DB 连接池、文件句柄)
对并行异步操作改用 Promise.allSettled
多个独立请求串着写 await,其中一个失败就会中断后续执行,还容易误以为错误已被捕获——其实只是没走到后面的 await。
- 把无依赖关系的异步任务统一发起:
const results = await Promise.allSettled([fetch(u), fetch(o), fetch(c)]) - 遍历
results,分别判断status === 'fulfilled'还是'rejected',按需处理或汇总上报 - 比
Promise.all更健壮,既避免连锁中断,也减少漏处理 rejection 的机会











