Search code examples
javascriptasync-awaites6-promiseecmascript-2016

Should await behavior be different when it is followed from a Promise rathen than a number?


I'm learning await/async keywords. My book says that the following code outputs from 1 to 9 instead of Firefox and Chrome output 1 2 3 4 5 8 9 6 7 and I'm agreeing with the browsers. My book puts the accent about a different behaviour when await is followed from a Promise. Namely await Promise.resolve(1) would be different from await 1 in the way the handlers are put in the Queue and it speacks about different queues. Is this a book mistake? In my understanding when an await 6 is encountered 6 is converted to Promise(6), then Promise(6).then(handler) happens behind the scene, the synchronous mode execution is interrupted, the Promise has already resolved thus the handler is put in the Job Queue. The control passes to the calling function that continues to run the remaining synchronous extern code. Later the handler in the Job Queue is executed and it executes the remaining code in the bar function thus in an asynchronous way. await 6 will return 6.

When I exec Promise.resolve(8) the same thing should happen and 8 will be printed before than 6 because the foo function is called first and thereby the handler is put first in the Job Queue.

Am I missing something? is it a book error or in the meanwhile is changed something, or could be that this specific behavior is browser dipendent because it isn't specified in the ecmascript specification? Furthermore I would know if is changed something in the Event Loop/Message Queue/Job Queue mechanism with the introduction of async/await ()

async function foo(){
  console.log(2);
  console.log(await Promise.resolve(8));
  console.log(9);
}

async function bar(){
   console.log(4);
   console.log(await 6);
   console.log(7);
}

console.log(1);
foo();
console.log(3);
bar();
console.log(5);

Here there are the pages of the book with the related code and explication. Page1

Page2


Solution

  • Book author here!

    When this chapter was written I was testing on Firefox v64 (and their contemporary vendor versions). If you install this version of the browser, you will find that the example works correctly.

    I narrowed down the breaking release to Firefox 69, which was released a few months after this chapter was written and tested by the editing team. You will note that in the release notes, under the "APIs" section there is a bullet "The Microtask API (WindowOrWorkerGlobalScope.queueMicrotask()) has been implemented".

    The relevant section from the HTML specification reads as follows:

    ...the best way of thinking about queueMicrotask() is as a mechanism for rearranging synchronous code, effectively placing the queued code immediately after the current task's worth of non-queued JavaScript.

    The promise implementation in modern browsers makes use of the microtask API, which changes the order that this example executes in. Specifically, the example in the book makes use of the behavior where await Promise.resolve(8) would effectively delay this log statement two cycles - once for the await, once for the Promise.resolve(). Now that promises use the microtask queue, this is no longer the case, and therefore the log output in the book is incorrect.

    This error was reported earlier this year and is being removed from the book.