Search code examples
javascriptasynchronouses6-promise

JavaScript: Will code in async functions before the first awaited promise run synchronously?


Given the following:

function defer(delay) {
  return new Promise((resolve) => setTimeout(resolve, delay));
}

let a;
(async () => {
  a = 1;
  await defer(1000);
  a = 2;
})();
console.log(a); // 1

Do I have a guarantee across all engines and transpilations that the value of a after the async function invocation is 1 and not undefined? In other words, is the code before the first await statement executed synchronously?


Solution

  • In other words, is the code before the first await statement executed synchronously?

    Yes.

    It is specified in 25.7.5.1 of the spec:

    25.7.5.1 AsyncFunctionStart ( promiseCapability, asyncFunctionBody )

    [logic for resuming the execution somewhen]

    1. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.

    2. Resume the suspended evaluation of asyncContext. Let result be the value returned by the resumed computation.

    3. Assert: When we return here, asyncContext has already been removed from the execution context stack and runningContext is the currently running execution context.

    4. Assert: result is a normal completion with a value of undefined. The possible sources of completion values are Await or, if the async function doesn't await anything, the step 3.g above.

    This operation gets run when you call an async function, and as you can see it directly executes the asyncContext without waiting for anything. If the engine reaches the await however, it actively halts the execution:

    6.2.3.1 Await

    [set up logic to continue somewhen]

    1. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.