When I run the following program
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)
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);
});
This is the output
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.
Because in the first code, everything up until the
Error
is on the same tick of the event loop.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.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, theError
is called afterawait
ing asetTimeout
call. When thesetTimeout
is done. The event loop puts the callback back into the stack, for this, the call stack must be empty.So now, you don't have
functionTwo
&functionThree
on the call stack, that's why they don't appear.The stack trace is the state of the stack when the error ocurred.
Here's a rough interpretation of what happens with the stack in both codes:
First Code
Second Code
I recommend watching this video to understand how all of this works:
What the heck is the event loop anyway by Philip Roberts
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.You can read a little bit more about this at https://v8.dev/blog/fast-async