async and await
In a promise chain, each step lives in its own callback, and the code does not read from top to bottom. The words async and await let you write waiting as ordinary lines.
Picture the cook again. A bread recipe has the step "wait for the dough to rise". The cook does not stand over the bowl for an hour: he puts a bookmark in the recipe and cooks other orders. When the dough has risen, he opens the recipe at the bookmark and goes on from the next step. Let's see how this looks in code:
function wait(ms, value) {
return new Promise((resolve) => {
setTimeout(() => resolve(value), ms);
});
}
async function main() {
const name = await wait(100, "Ann");
console.log(name);
}
main();
console.log("after main");
// after main
// AnnLet's take the example apart:
- The
waitfunction returns a promise that is fulfilled withvalueaftermsmilliseconds. - Inside
main, the line withawaitwaits for that and puts"Ann"into the constantname. - The next line,
console.log(name), runs only after that and printsAnn.
So the code inside main reads from top to bottom, as if there were no wait. One function may hold many await lines: each of them waits for its own promise in turn.
A function with async
The word async before function makes the function an async function. Such a function always returns a promise, and the value after return becomes that promise's value:
async function one() {
return 1;
}
const p = one();
console.log(typeof p); // object
console.log(p instanceof Promise); // true
p.then((v) => console.log(v)); // 1What happens here:
one()returns a promise, not the number1;- for a promise, as for an array,
typeofgives"object"; instanceof Promisetells a promise apart from other objects;- the number
1itself is taken withthenor withawait.
Interviewers like to ask what a call to an async function returns. The answer: a promise, even if the body says return 1.
What await does
await pauses only its own async function, until the promise on its right is no longer pending. The rest of the program keeps running meanwhile. That is the bookmark in the recipe: the cook set one recipe aside, not the whole kitchen.
That is why after main prints before Ann in the first example. When main reached the await, the call main() returned a promise, and the next line ran.
Even when the promise is already fulfilled, the rest of the function waits, like a then callback, until the current code ends.
Here the cook analogy stops working. A cook may forget where he stopped, but the function resumes exactly at the line after await, with all its variables in place.
Rejection and try…catch
If the promise is fulfilled, await gives its value. If the promise is rejected, await throws its reason, like throw. Such an error is caught with an ordinary try…catch:
async function load() {
try {
await Promise.reject(new Error("no network"));
console.log("loaded");
} catch (e) {
console.log(e.message);
}
}
load();
// no networkPromise.reject(reason) creates a promise that is already rejected. The loaded line is skipped: after the throw, execution moves to catch.
If an error inside an async function is not caught, the function does not crash on the spot. The promise it returned becomes rejected with that error, and it can be caught outside: load().catch((e) => …). Inside the function, try…catch is usually handier: the handling sits next to the line that waits.
That is why try…catch around a call without await does not catch such an error. The call itself throws nothing: it returns a promise at once, and only catch and await see that promise's rejection.
Common mistake
await is written in a function without async:
function show() {
const name = await wait(100, "Ann"); // ✗
console.log(name);
}SyntaxError: await is only valid in async functions and the top level bodies of modulesThis is a SyntaxError, so the file does not run at all, even if show is never called. The end of the message is about modules, files with import and export. The course does not use them, and in an ordinary file await works only inside an async function. Add async before function.
Key points
- An
asyncfunction always returns a promise, and the value afterreturnbecomes its value. awaitpauses only its own function until the promise is no longerpending; the rest of the program goes on.awaitthrows a rejected promise's reason as an error, andtry…catchcatches it.awaitworks only inside anasyncfunction.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.