What you'll learn
Promises represent future completion. async/await makes dependent steps readable, while promise combinators express concurrency, tolerance, racing, and aggregate failure.
By the end of this lesson, you'll be able to:
- Chain and await promises
- Select the correct promise combinator
- Cancel cooperative work with AbortController
Core mental model
Use this decision table as a compact reference. Focus on what each tool means and when it earns its place in production code.
| Concept | What it means | Decision rule |
|---|---|---|
| Promise | Eventually fulfilled or rejected result | Return it so callers own completion |
| async/await | Syntax for promise-based sequencing | Use try/catch at the boundary that can recover |
| Combinator | Coordinates multiple promises | Choose all, allSettled, race, or any from failure semantics |
Professional workflow
Build the behavior in small, observable steps. Each step should leave something you can inspect or test.
- Describe the promise operation boundary: inputs, outputs, state, timing, and expected failures.
- Implement the smallest correct path with names that expose intent.
- Add edge cases and failure handling before introducing abstractions.
- Verify behavior with realistic data and one deliberately adversarial example.
- Refactor only after the observable behavior is protected.
Make behavior observable
Guided code lab
Run independent work concurrently
Start both operations before awaiting their combined result.
async function loadDashboard() {
const profilePromise = loadProfile();
const coursesPromise = loadCourses();
const [profile, courses] = await Promise.all([profilePromise, coursesPromise]);
return { profile, courses };
}Add cooperative cancellation
The caller owns the controller and the operation observes its signal.
async function loadJson(url, signal) {
const response = await fetch(url, { signal });
if (!response.ok) throw new Error("HTTP " + response.status);
return response.json();
}
const controller = new AbortController();
loadJson("/api/course", controller.signal).catch(error => {
if (error.name !== "AbortError") console.error(error);
});
controller.abort();Production practice
Contract
Document the promise operation inputs, completion signal, failure channel, ordering, and cancellation behavior.
Verification
Test success, expected failure, timeout or cancellation, empty data, and out-of-order completion.
Operations
Expose duration and failure context without logging secrets or overwhelming the main thread.
Common failure mode
Independent workshop
Build a resilient dashboard loader with required and optional resources.
Your finished workshop must include:
- Promise.all for required data
- allSettled for optional panels
- Cancellation and typed error messages
Definition of done
Recap & quick check
Key takeaways
- Promises represent one future result
- async functions always return promises
- Concurrency starts before await
- Cancellation must be designed into APIs
Quick check
1. What does an async function return?
2. Which combinator waits for every outcome without failing fast?
3. Who should usually own cancellation?
Keep the workshop. Later modules deliberately build on these decisions, so each exercise can become part of your final portfolio architecture.