16. async / await
Adding the `async` keyword wraps a function's return value in a Promise automatically.
What you'll learn
- 1Know that an `async` function always returns a Promise.
- 2Use `await` to read a Promise's value as if it were synchronous.
- 3Handle async errors with `try/catch`.
- 4Distinguish parallel from sequential execution.
- 5Combine `Promise.all` with `await` for efficient parallel work.
Overview
Adding the `async` keyword wraps a function's return value in a Promise automatically.
Core Concepts
1. async functions
Adding the `async` keyword wraps a function's return value in a Promise automatically.
async function f() {
return 42;
}
f().then((v) => console.log(v)); // 422. await
`await` pauses the function until the Promise settles. You can only use it inside an `async` function (except top-level await in modules).
async function main() {
const value = await Promise.resolve(10);
console.log(value); // 10
}3. try / catch
Use try/catch to handle async errors.
async function load() {
try {
const data = await fetchData();
console.log(data);
} catch (err) {
console.error(err);
}
}4. Parallel vs sequential
Back-to-back `await`s wait for each previous task to finish, which is slow. Run independent tasks in parallel with `Promise.all`.
// slow (sequential)
const a = await fetchA();
const b = await fetchB();
// fast (parallel)
const [a, b] = await Promise.all([fetchA(), fetchB()]);Examples
| File | What it covers |
|---|---|
| 01_async_basic.js | Basics of async functions and await |
| 02_try_catch.js | Error handling with try/catch |
| 03_promise_all.js | await + Promise.all |
| 04_parallel.js | Parallel vs sequential timing |
src/01_async_basic.js
/**
* Basics of async/await.
*/
function delay(ms, value) {
return new Promise((resolve) => setTimeout(() => resolve(value), ms));
}
async function main() {
console.log("start");
const value = await delay(200, "hello!");
console.log("got:", value);
console.log("end");
}
main();
src/02_try_catch.js
/**
* Handle async errors with try/catch.
*/
function fetchData(ok) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (ok) resolve({ id: 1 });
else reject(new Error("network failed"));
}, 100);
});
}
async function run() {
try {
const data = await fetchData(false);
console.log("ok:", data);
} catch (err) {
console.error("error:", err.message);
} finally {
console.log("cleanup");
}
}
run();
src/03_promise_all.js
/**
* Combine await with Promise.all for parallel results.
*/
function fetchValue(label, ms) {
return new Promise((resolve) => setTimeout(() => resolve(label), ms));
}
async function loadAll() {
const [a, b, c] = await Promise.all([
fetchValue("A", 100),
fetchValue("B", 200),
fetchValue("C", 150),
]);
console.log("all values:", a, b, c);
}
loadAll();
src/04_parallel.js
/**
* Compare timing of sequential await vs parallel await (Promise.all).
*/
function work(label, ms) {
return new Promise((resolve) => setTimeout(() => resolve(label), ms));
}
async function sequential() {
const start = Date.now();
await work("A", 200);
await work("B", 200);
await work("C", 200);
console.log("sequential:", Date.now() - start, "ms");
}
async function parallel() {
const start = Date.now();
await Promise.all([work("A", 200), work("B", 200), work("C", 200)]);
console.log("parallel:", Date.now() - start, "ms");
}
(async () => {
await sequential();
await parallel();
})();
Common Mistakes
- Using `await` outside an `async` function β SyntaxError.
- Writing independent tasks as sequential `await`s and wasting time.
- Skipping try/catch around an `await` and triggering an unhandled rejection.
- `forEach((x) => await ...)` doesn't actually wait β the callback isn't async.
- Forgetting that an `async` function returns a Promise and using the result directly.
FAQ
Q1. Can I use `await` at the module top level?
Yes β top-level await in ES modules (ES2022).
Q2. What happens if an async function throws?
Its returned Promise becomes rejected.
Q3. Should I prefer await or .then?
`await` usually reads better. `.then` can still be cleaner for simple branches and compositions.
Practice
- Use an async function to fetch a user and then their posts sequentially.
- Simulate parallel calls to multiple URLs with Promise.all.
homework/README.md
## 1. User + posts β Write fake `fetchUser(id)` and `fetchPosts(userId)`, then chain them in an async function and print the result.
## 2. Parallel requests β Start three fake URL requests with Promise.all and measure the total time.
See the `answer/` directory for solutions.
homework/answer/homework_01.js
/**
* Fetch a user, then fetch their posts.
*/
function fetchUser(id) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id, name: "Jimin" }), 100);
});
}
function fetchPosts(userId) {
return new Promise((resolve) => {
setTimeout(() => resolve([{ id: 1, userId, title: "First post" }]), 100);
});
}
async function main() {
try {
const user = await fetchUser(1);
const posts = await fetchPosts(user.id);
console.log(user.name, "'s posts:", posts);
} catch (err) {
console.error(err);
}
}
main();
homework/answer/homework_02.js
/**
* Send three fake URL requests in parallel and measure total time.
*/
function fakeFetch(url, ms) {
return new Promise((resolve) => setTimeout(() => resolve(`${url} OK`), ms));
}
async function main() {
const start = Date.now();
const results = await Promise.all([
fakeFetch("/a", 200),
fakeFetch("/b", 250),
fakeFetch("/c", 150),
]);
console.log("results:", results);
console.log("total time:", Date.now() - start, "ms");
}
main();
Next Lecture
[17_DOM_Selection_and_Inspection](../../05_DOM/17_DOM_μ νκ³Ό_μ‘°ν/) β Working with HTML elements in the browser.
All lecture materials and example code are openly available on GitHub.
View on GitHub β