dob*_*ler 11 callstack node.js async-await
根据文档,我假设 Node.js 14 现在确实支持异步代码中的堆栈跟踪,但不幸的是,使用node --async-stack-traces test.js仍然只生成部分堆栈跟踪,我最有兴趣了解原因。
运行以下代码:
main()
function main() {
sub();
}
async function sub() {
console.trace('before sleep');
await delay(1000);
console.trace('after sleep');
}
function delay(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
}
Run Code Online (Sandbox Code Playgroud)
显示使用之前的完整堆栈,但仅显示使用之后的部分堆栈await:
~/MyDev/doberkofler/test $ node test.js
Trace: before sleep
at sub (/Users/doberkofler/MyDev/doberkofler/test/test.js:10:10)
at main (/Users/doberkofler/MyDev/doberkofler/test/test.js:6:2)
at Object.<anonymous> (/Users/doberkofler/MyDev/doberkofler/test/test.js:3:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47
Trace: after sleep
at sub (/Users/doberkofler/MyDev/doberkofler/test/test.js:12:10)
~/MyDev/doberkofler/test $
Run Code Online (Sandbox Code Playgroud)
Dav*_*sel 10
异步堆栈跟踪将起作用,但仅适用于不间断的异步方法链。因此,要修复您的示例,请使您的 main 方法异步,然后等待对 sub 的调用。
如果你使用承诺,或者在返回之前错过等待,那么它就会中断。
此处对此进行了解释:https ://github.com/nodejs/node/issues/36126#issuecomment-827023528
这并不是一个错误,而只是v8 实现的零成本异步堆栈跟踪机制的限制。
具体来说,我们看一下原来的例子:
Run Code Online (Sandbox Code Playgroud)main() function main() { sub(); } async function sub() { console.trace('before sleep'); await delay(1000); console.trace('after sleep'); } function delay(ms) { return new Promise(resolve => { setTimeout(() => resolve(), ms); }); }这
main是一个常规的同步函数。它调用sub()在 的调用堆栈范围内console.trace('before sleep')同步触发。main()这就是为什么before sleep包含完整的堆栈跟踪信息。接下来发生的事情是,main()在微任务队列稍后触发console.trace('after sleep'). 当第二个console.trace()被调用时,main()callstack 早已消失,有关它的信息不再存在,v8 无法对其执行任何操作。虽然sub()看起来它是一个单一的调用堆栈,但实际上它是随着时间的推移分散的多个调用堆栈。为了
after sleep获得完整的堆栈跟踪, 的调用者sub()必须是异步函数,并且调用必须sub()使用await。例如:Run Code Online (Sandbox Code Playgroud)main() async function main() { await sub(); } async function sub() { console.trace('before sleep'); await delay(1000); console.trace('after sleep'); } function delay(ms) { return new Promise(resolve => { setTimeout(() => resolve(), ms); }); }这如何改变事情?好吧,创建
main()异步并拥有它await sub()意味着 v8 必须保留调用堆栈信息main()直到sub()完成 - 也就是说,完整的调用堆栈信息main()仍将驻留在内存中并且可以轻松地供 v8 使用。当第二次调用console.trace()发生时(并且它创建用于生成打印堆栈的内部Error对象,所有调用堆栈详细信息将随时可用,并且生成仅返回到最顶层异步函数的正确错误堆栈await:Run Code Online (Sandbox Code Playgroud)Trace: before sleep at sub (/root/node/tmp/f.js:8:13) at main (/root/node/tmp/f.js:4:10) at Object.<anonymous> (/root/node/tmp/f.js:1:1) at Module._compile (node:internal/modules/cjs/loader:1108:14) at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10) at Module.load (node:internal/modules/cjs/loader:988:32) at Function.Module._load (node:internal/modules/cjs/loader:828:14) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12) at node:internal/main/run_main_module:17:47 Trace: after sleep at sub (/root/node/tmp/f.js:10:13) at async main (/root/node/tmp/f.js:4:4)最重要的是,它绝对不是一个错误。异步堆栈跟踪机制完全按照其设计的方式工作——它只是限制了它可以捕获的信息。现在,是否可以改进是次要讨论,但 Node.js 中没有错误,因为我们完全依赖 v8 在这里提供的内容。
| 归档时间: |
|
| 查看次数: |
5769 次 |
| 最近记录: |