我有以下简化代码:
async function fun() {
function fun1() {
return Promise.resolve(
new Promise((resolve, reject) => {
resolve();
}),
);
}
function fun0() {
return fun1().then((_) => {
return new Promise((resolve, reject) => {
console.log(new Error().stack);
});
});
}
fun0();
}
(async () => {
await fun();
})();
我的目标是获得完整的调用堆栈。但是,上面的输出仅包含匿名 Promise 的位置,而不包含
fun0
或 fun1
。
有没有办法在 v8 中获取整个堆栈跟踪?
您的问题有点误导,因为您所看到的实际上是当前堆栈 - 一旦触发异步操作(在您的情况下通过调用
resolve()
安排 Promise 的结算)同步执行将继续,堆栈将展开直到它最终是空的。然后,在某个时刻,异步事件被推入任务队列并最终被拾取,调用 Promise 中存储的 then-handler。因此,您看到的实际上是堆栈(如 - V8 调试器根据执行的内部表示将其重建为逻辑堆栈)。
也就是说,V8 实际上可以跟踪和“异步堆栈”——这意味着每当异步事件发生时,它都会存储当前堆栈(作为某种字符串)并将其附加到异步事件。然后,当事件完成并且任务被拾取时,它将存储的堆栈和异步堆栈缝合在一起 - 有关更多详细信息,请参阅此相关问题。由于这会带来相当大的开销,因此仅当在 Chrome 中打开调试器时才会存储堆栈 - 我想可以通过将调试器附加到正在运行的 NodeJS 进程来触发相同的操作。