Node中的异步堆栈跟踪

6

我有点惊讶,自己竟然没有遇到过这种情况。但是,在另一个tick中执行的回调函数中创建的node错误将不会有一个清晰的堆栈跟踪。

例如:

function base (cb)  {
  process.nextTick(() => {
    throw new Error("I am unhelpful")
  }, 1000)
}

function top (cb) {
  base(cb)
}

top(() => {})

结果为:

Error: I am unhelpful
    at /Users/me/stacktrace.js:45:11
    at _combinedTickCallback (internal/process/next_tick.js:135:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

当例外发生在执行异步操作的库中的回调/承诺时,特别糟糕,因为没有易于返回追踪以找到问题代码的路径。想象一下涉及控制器、一些辅助模块和第三方库的服务调用。

我的解决方案是在当前刻创建潜在失败情况的错误,然后如果有错误,将其通过:

function base (cb)  {
  let potentialError = new Error('oh noes')
  process.nextTick((err) => {
    potentialError.message = err.message
    throw potentialError
  }, 1000)
}

这个可以给我一个包含调用链的堆栈跟踪:

Error: oh noes
    at base (/Users/me/stacktrace.js:47:24)
    at top (/Users/me/stacktrace.js:43:3)
    at Object.<anonymous> (/Users/me/stacktrace.js:53:1)

我知道像superstack这样的模块,但它们会进行猴子补丁(error monkey patch),并且似乎无法与较新版本的node一起使用。

核心本身只是在异步堆栈跟踪(async stack traces)中内置了支持,但这是一个实验性/开发人员专用功能,不建议在生产环境中使用。

是否有更好的方法来实现我的需求?


处理承诺时,有一种很好的处理方式。但对于一般的异步回调……就不那么容易了。 - Kevin B
我认为在我的情况中,罪魁祸首实际上是http,它在这里使用了nextTickhere。无论异步模式如何包装调用,堆栈跟踪仍然丢失:\ - Nick Tomlin
正确的做法是将nextTick转换为promise,这样才能在promise中正确地抛出异常。如果你在.then中抛出异常,它会被传递到.catch中。但是,如果你在稍后创建的promise中抛出异常,或者从解决promise的某个地方抛出异常,它就不会被传递。 - Kevin B
1个回答

2
这现在对于使用async关键字的函数(而不是所有异步函数)在node 12.x中通过--async-stack-traces命令行标志可用。希望最终能够在所有地方标准化。
更多细节请参见发布说明功能文档
目前不支持非async函数,遗憾。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接