优先用 async/await 替代 then 链以保留完整异步堆栈;必要时通过手动挂载 context 字段、AsyncLocalStorage 或全局 unhandledRejection 监听补全上下文与兜底。

核心办法是避免 Promise.then 链式接力,改用 async/await 保持执行上下文连续性;当必须用链式调用时,通过手动挂载关键信息或运行时上下文机制补全断点。
优先用 async/await 替代 then 链
Promise.then 会切断原始调用栈,而 await 在 V8(Node.js 14+ / Chrome 89+)中被引擎特殊优化,能保留从入口函数到错误抛出处的完整异步堆栈。
- 错误写法:堆栈只剩回调层
- 正确写法:所有 await 调用都在同一逻辑上下文中展开,报错时 stack 显示 placeOrder → validateItems → lockStock
- 注意:必须使用原生 Promise;混用 then 和 await 会破坏堆栈还原能力
手动注入上下文字段
适用于无法重构成 async/await 的旧代码或第三方库回调场景。把请求 ID、用户标识、操作阶段等关键信息作为属性附加到 Error 实例上。
- 在每个异步步骤的 catch 中捕获错误,扩展 context 字段再 re-throw
- 日志系统统一读取 error.context,而非只依赖 stack 字符串
- 示例:
err.context = { userId, orderId, step: 'lockStock' }
用 AsyncLocalStorage 穿透异步边界(Node.js)
基于 async_hooks 实现,可将数据与整个异步生命周期绑定,无需手动透传参数。
立即学习“Java免费学习笔记(深入)”;
- 初始化一个存储实例,在入口处 run() 绑定上下文对象
- 后续任意深度的异步回调中,调用 getStore() 即可取回原始上下文
- 适合微服务请求链路追踪,天然支持中间件、数据库调用、消息发送等场景
启用未处理拒绝全局监听
兜底保障:捕获漏掉 .catch() 或未 await 的 Promise 拒绝,防止错误静默丢失。
- 浏览器中监听
unhandledRejection事件 - Node.js 中监听
process.on('unhandledRejection') - 结合 console.trace() 或自定义日志,至少保留当前异步任务的简易调用路径


















