Node.js v14下如何获取JS错误实际抛出位置而非创建位置
解决方案
你可以通过V8引擎暴露的Error.prepareStackTrace接口,结合临时重写错误的stack属性获取抛出时的堆栈,Node.js v14完全支持该特性。
具体实现方案
方案1:全局监控缓存错误的二次抛出
如果你无法修改第三方库的缓存逻辑,可以在全局捕获错误的位置(比如未捕获异常监听),先重新生成当前堆栈再打印:
process.on('uncaughtException', (err) => { // 临时创建一个新错误获取当前堆栈,里面就包含抛出位置 const currentStackErr = new Error(); Error.captureStackTrace(currentStackErr); console.log('错误原始堆栈:', err.stack); console.log('错误抛出位置堆栈:', currentStackErr.stack); process.exit(1); });
你提供的示例代码运行后,currentStackErr.stack会明确显示抛出位置在f函数中。
方案2:修改错误实例自动捕获抛出位置
如果可以对缓存的错误实例做改造,你可以重写错误的stack属性的getter,在第一次访问(通常是抛出后打印时)自动捕获当前堆栈:
function wrapError(err) { let cachedThrowStack = null; Object.defineProperty(err, 'stack', { get() { if (!cachedThrowStack) { const stackErr = new Error(); Error.captureStackTrace(stackErr, wrapError); cachedThrowStack = stackErr.stack; } return `创建位置堆栈:\n${err.originalStack}\n\n抛出位置堆栈:\n${cachedThrowStack}`; } }); err.originalStack = err.stack; return err; } // 对第三方库缓存的错误做包装 const err = wrapError(new Error()); function f() { throw err; } f();
运行后打印的堆栈会同时包含创建和抛出两个位置的信息。
注意事项
Error.captureStackTrace的第二个参数是要排除的堆栈帧,传入对应的包装函数可以避免堆栈里出现你自己的包装逻辑,更易读。- 如果你的Node.js开启了source map,需要确保堆栈解析逻辑兼容两个堆栈的映射。
内容的提问来源于stack exchange,提问作者Tim Perry
相关产品推荐
相关产品推荐

