I have such a piece of code
async function loop() {
for (let i = 0; i < 3; i++) {
console.log(i,new Error("").stack);
await 1;
}
}
loop();
when I run it in Node (Chrome engine) I get this:
0 Error
at loop (file:///Users/user/Desktop/test.mjs:3:19)
at file:///Users/user/Desktop/test.mjs:8:1
at ModuleJob.run (node:internal/modules/esm/module_job:217:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:308:24)
at async loadESM (node:internal/process/esm_loader:42:7)
at async handleMainPromise (node:internal/modules/run_main:66:12)
1 Error
at loop (file:///Users/user/Desktop/test.mjs:3:19)
2 Error
at loop (file:///Users/user/Desktop/test.mjs:3:19)
so it seems that after await the execution loses its broader context but retains the context of the function.
When I run the same piece of code in Bun (Safari engine) I get this:
0 Error:
at <anonymous> (/Users/user/Desktop/test.mjs:3:10)
at loop (/Users/user/Desktop/test.mjs:1:22)
at module code (/Users/user/Desktop/test.mjs:5:5)
1 Error:
at <anonymous> (/Users/user/Desktop/test.mjs:3:10)
2 Error:
at <anonymous> (/Users/user/Desktop/test.mjs:3:10)
which says that the execution loses even the context of the function.
Now, I know what happens when I use await like this, more or less. It forces stuff to be pushed to the micro task queue, lets the rest of the sync code on the stack execute, therefore we lose the stack, and picks up the stuff pushed to the queue afterwards.
However, I'm interested in how exactly this happens and looking at these different errors stacks I'm really confused. Are we in the same function after using await or is a new function created somehow with the context of the previous one?

I assume with "context" you refer to the execution contexts of the callers of the function. These contexts have been closed normally by their synchronous execution, while the execution context of the function itself is suspended.
An important realisation here is that the
asyncfunction returns when it has evaluated anawaitexpression. It returns a promise, and the call stack (what you call the "context") will run to completion. The call stack is empty, and will not be restored. Restoring it would make no sense, as it would indicate that a caller would get twice (or more) a return value from theasyncfunction, and code that follows that call would have to execute twice (or more) as well. A function only returns once to its caller.So once the microtask is consumed, the execution context of the
asyncfunction will be restored. But this does not include a restored call stack.It is the same function -- it is resumed. See this as a new call of the function, but where it starts with a saved execution context, and continues from there. This time the caller is the event loop, so the call stack starts from scratch. When the
asyncfunction executes areturn, this return value will be used by the engine to resolve the promise that was returned to the original caller.