Consecutive awaits
The second operation starts after the first finishes.
These are three ways to handle work that finishes later, such as loading data from a server, reading a file, or waiting for a timer.
Some operations do not produce a result immediately. A network request might take 200 milliseconds or several seconds.
JavaScript starts the operation and continues running other code. You need a way to say, “When the result is ready, run this code.”
const user = getUser(42);
console.log(user.name);
Callbacks, Promises, and async/await provide different ways to wait for that result.
A callback is a function passed to another function. The other function calls it when the work is complete.
getUser(42, (error, user) => {
if (error) {
console.error(error);
return;
}
console.log(user.name);
});
getUser starts the request.getUser calls the callback with an error or a user.A callback is just a function. Callbacks can also be used for synchronous operations, but they are common in asynchronous APIs.
getUser(42, (error, user) => {
if (error) return handleError(error);
getPosts(user.id, (error, posts) => {
if (error) return handleError(error);
showPosts(posts);
});
});
The repeated error checks and increasing indentation become difficult to manage as more steps are added.
A Promise is an object that represents one result that may become available later.
A Promise is always in one of three states:
.then() handles a fulfilled value. .catch() handles a rejection.
getUser(42)
.then(user => {
console.log(user.name);
})
.catch(error => {
console.error(error);
});
Promises are useful because they can be chained. Each .then() produces a new Promise.
getUser(42)
.then(user => {
return getPosts(user.id);
})
.then(posts => {
showPosts(posts);
})
.catch(handleError);
If you forget to return getPosts(), the next .then() will run without waiting for it.
Async/await is another way to work with Promises. It does not replace Promises.
An async function always returns a Promise. Inside that function, await waits for a Promise to settle.
async function showUser() {
try {
const user = await getUser(42);
console.log(user.name);
} catch (error) {
console.error(error);
}
}
showUser();
getUser(42) returns a Promise.await pauses showUser until that Promise settles.user receives the value.catch.await pauses only the current async function. It does not block the entire JavaScript program.
async function loadPosts() {
try {
const user = await getUser(42);
const posts = await getPosts(user.id);
showPosts(posts);
} catch (error) {
handleError(error);
}
}
Use consecutive awaits when the second operation needs the first result.
const user = await getUser(42);
const posts = await getPosts(user.id);
If operations do not depend on each other, start them together with Promise.all().
const [user, settings] = await Promise.all([
getUser(42),
getSettings()
]);
The second operation starts after the first finishes.
Both operations start immediately, then the code waits for both.
| Style | Success | Failure |
|---|---|---|
| Callback | Callback argument | Error argument |
| Promise | .then() |
.catch() |
| Async/await | await |
try/catch |
It usually makes dependent steps easier to read.
For example, click handlers and older Node.js APIs.
This keeps errors and completion connected to the caller.
This avoids waiting longer than necessary.
What does a callback provide to an asynchronous function?
It provides the code to run after the operation finishes. The asynchronous function calls the callback with the result or an error.
What are the three states of a Promise?
Pending means the operation has not finished. Fulfilled means it completed successfully and produced a value. Rejected means it failed and produced an error.
Does await block the entire JavaScript program?
No. It pauses only the current async function. Other JavaScript can continue running while the function waits for the Promise.
When should you use Promise.all() instead of consecutive awaits?
Use it when the operations are independent. They can start together, which usually finishes sooner than waiting for each one separately.
What does this code print?
Promise.resolve(2)
.then(number => number * 3)
.then(console.log);
It prints 6. The first .then() receives 2 and returns 6. The next .then() receives that returned value.
In what order does this code print the letters?
async function run() {
console.log("A");
await Promise.resolve();
console.log("B");
}
run();
console.log("C");
It prints A, C, then B. Calling run() prints A. The await pauses run, so the program continues and prints C. Then run resumes and prints B.
What does this code print?
async function run() {
try {
await Promise.reject("Failed");
console.log("Done");
} catch (error) {
console.log(error);
}
}
run();
It prints Failed. Awaiting the rejected Promise moves execution directly to catch, so Done is never printed.