为什么在Node.js中使用async-await时会丢失堆栈跟踪?

为什么在Node.js中使用async-await时会丢失堆栈跟踪?

问题描述:

当我运行以下程序时

async function functionOne() {

  throw new Error('Error here prints the complete stack');

  await new Promise((resolve) => {
    setTimeout(() => { resolve(); }, 1000);
  });
}

async function functionTwo() {
  await functionOne();
}

async function functionThree() {
  await functionTwo();
}

functionThree()
  .catch((error) => {
    console.error(error);
  });

我得到以下输出,该输出通过各种调用的函数打印堆栈

I get the following output which prints the stack through the various invoked functions

Error: Error here prints the complete stack
    at functionOne (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:3:9)
    at functionTwo (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:11:9)
    at functionThree (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:15:9)
    at Object.<anonymous> (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:18:1)
    at Module._compile (module.js:612:30)
    at Object.Module._extensions..js (module.js:623:10)
    at Module.load (module.js:531:32)
    at tryModuleLoad (module.js:494:12)
    at Function.Module._load (module.js:486:3)
    at Function.Module.runMain (module.js:653:10)

但是在以下程序中的await调用后引发错误时

However when the error is thrown after the await call in the following program

async function functionOne() {

  await new Promise((resolve) => {
    setTimeout(() => { resolve(); }, 1000);
  });

  throw new Error('Error here prints incomplete stack');

}

async function functionTwo() {
  await functionOne();
}

async function functionThree() {
  await functionTwo();
}

functionThree()
  .catch((error) => {
    console.error(error);
  });

这是输出

Error: Error here prints incomplete stack
    at functionOne (/home/divyanshu/programming/errorHandlingAsyncAwait/index.js:7:9)
    at <anonymous>

我想了解为什么在第二种情况下而不是在第一种情况下会丢失堆栈跟踪.

I'd like to understand why the stack trace is lost in the second case but not in the first.

因为在第一个代码中,直到Error之前的所有内容都与事件循环的同一滴答处一样.

Because in the first code, everything up until the Error is on the same tick of the event loop.

在异步回调之前,setTimeout中的一个可以进入调用堆栈(堆栈跟踪是从该堆栈建立的),调用堆栈必须为空.

Before an asynchronous callback, the one from setTimeout, can enter the call stack (The stack trace is built from it), the call stack must be empty.

因此,由于第一个代码同步运行所有内容,直到Error调用为止,因此所有这些调用都在调用堆栈中.但是在第二种方法中,在await调用setTimeout之后调用Error. setTimeout完成后.事件循环将回调放回堆栈中,为此,调用堆栈必须为空.

So since the first code runs everything synchronous until the Error call, all those calls are in the call stack. But on the second approach, the Error is called after awaiting a setTimeout call. When the setTimeout is done. The event loop puts the callback back into the stack, for this, the call stack must be empty.

因此,现在您没有functionTwo& functionThree在调用堆栈上,这就是为什么它们不出现的原因.

So now, you don't have functionTwo & functionThree on the call stack, that's why they don't appear.

T 堆栈跟踪是发生错误时堆栈的状态.

以下是两种代码中堆栈发生的情况的粗略解释:

Here's a rough interpretation of what happens with the stack in both codes:

第一个密码

1) functionThree is pushed into the stack
2) functionTwo is pushed into the stack
3) functionOne is pushed into the stack
4) Error is thrown

第二个代码

1) functionThree is pushed into the stack
2) functionTwo is pushed into the stack
3) functionOne is pushed into the stack
4) awat ...setTimeout is called
5) All 3 functions return a Promise
6) The stack is empty

... setTimeout ends
Next tick of the event loop

1) setTimeout callback is called
2) Error is thrown

我建议观看此视频,以了解所有这些工作原理:

I recommend watching this video to understand how all of this works:

事件循环到底是什么

What the heck is the event loop anyway by Philip Roberts

在最新版本的Node.js上,使用异步代码时,可以使用--async-stack-traces标志来改善堆栈跟踪.

On the newests versions of Node.js you can use --async-stack-traces flag to have an improved stack trace when working with asynchronous code.

您可以在 https://v8.dev/blog/fast-异步