What is the await statement in Javascript
How Promise states and the async statement work to return an async value
Recently I got a question regarding a Promise that had two await
s:
// memo is a Promise
await memo;
await sleep(10);
return (await memo) + e;
Does having two await
s mean the Promise will be run twice? Or is it equal to this code:
// memo is a Promise
const res = await memo;
await sleep(10);
return res + e;
To understand what happens, we need to look into what the await
keyword does. And to do that, we first need to understand Promise states.
Promise states
When a Promise is created it starts in the Pending state. It means it has no value yet.
It does not matter how the Promise is constructed, be it with the Promise constructor or calling an async
function. In both cases, the Promise will be
Pending:
new Promise((res) => setTimeout(res, 100, "result"));
// Promise {<pending>}
(async () => {await fetch("https://advancedweb.hu")})();
// Promise {<pending>}
When the Promise is ready, it transitions to the Resolved or the Rejected state. Collectively, these are called Settled or Fulfilled. At this point, the Promise has a value, either a result (if it is resolved) or an error (if it's rejected).
A good illustration of how a Promise moves from Pending to Resolved is to wait a bit and print it again. In this code, the Promise resolves in 100ms, so the
second console.log
sees it as Fulfilled:
const prom = new Promise((res) => setTimeout(res, 100, "result"));
console.log(prom);
// Promise {<pending>}
setTimeout(() => console.log(prom), 150);
// Promise {<fulfilled>: "result"}
The await
keyword
So what does await
do? It waits for the Promise to be Fulfilled (Resolved or Rejected) and returns (or throws) its value.
The simplest example is to store the result value then print it to the console:
const prom = new Promise((res) => setTimeout(res, 100, "result"));
(async () => {
const res = await prom;
console.log(res);
// result
})();
First, prom
is Pending, i.e. without a value. The await prom
waits until the Promise becomes Resolved (the setTimeout
calls
the res()
function with "result"
) then returns the value.
You can think about that line as the await prom
becomes the result of the Promise:
const res = await prom;
// when the Promise resolves, this line becomes:
const res = "result";
And what happens if the Promise is already Fulfilled? The await
returns with the result without waiting.
Multiple await
s
To revisit the question from the beginning of this article, does the second await
makes the code run slower?
// memo is a Promise
await memo;
await sleep(10);
return (await memo) + e;
When this code starts, memo
is Pending. So the first await memo
stops and waits for it to be Fulfilled. But when the second
(await memo) + e
runs, memo
already has a value, so it returns immediately.