Checkpoint: Browser APIs
This checkpoint consolidates the async and browser-API skills you have built — promise combinators, async iterators, cancellation, workers, observers, storage, and canvas — into one recap, a real build challenge, and a quick quiz.
Learn Checkpoint: Browser APIs in our free JavaScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
If you can finish the challenge and answer the quiz, you are ready to ship features that fetch, stream, cache, and render real data.
What You'll Do in This Checkpoint
What You've Learned
Here is the whole stretch in one place. Skim it; anything that feels fuzzy is worth a quick revisit.
Topic
The one thing to remember
Promise combinators
all is fail-fast, allSettled keeps every result, race takes the first, any the first success.
Async iterators
async function* + for await stream values lazily, one await at a time.
AbortController
A one-shot signal cancels work; fetch rejects with an AbortError .
Web Workers
Heavy CPU work on another thread; talk only via postMessage ; data is cloned.
IntersectionObserver
Efficiently detect visibility for lazy loading and infinite scroll — no scroll polling.
MutationObserver
React to DOM changes (nodes, attributes, text) as batched records.
IndexedDB
A real client-side database: object stores, transactions, indexes — usually promise-wrapped.
Canvas API
Draw on the 2D context; top-left origin, radians for arcs, repaint each frame.
🛠️ Build Challenge — A Resilient Data Pipeline
Tie three skills together into one pipeline that real apps actually need:
- Fan-out fetch a batch of pages in parallel with Promise.allSettled , so one broken page does not sink the rest.
- Stream the items from the successful pages through an async generator paginator.
- Back it with a Map cache so a second pass refetches nothing.
The starter below already runs end to end against a fake paged API (page 2 fails on purpose). Read it, run it, then try extending it — for example add a real cachedFetch that consults the cache before hitting the network, then compare with the full solution.
📝 Checkpoint Quiz
Answer each one in your head first, then expand to check. Aim to explain the why .
Promise.allSettled . It never rejects and returns a result object per promise, so you keep the successes and can count the failures.
for await (const x of gen()) , and it must live inside an async function. A plain for-of throws on an async iterable.
Its promise rejects with a DOMException named "AbortError" . Check err.name so you can ignore deliberate cancellations.
Messages are copied with the structured clone algorithm, which cannot clone functions or DOM nodes — it throws a DataCloneError . Send plain data only.
rootMargin (e.g. "200px 0px" ) on an IntersectionObserver . It expands the viewport box so elements count as visible early.
Stores are created only inside onupgradeneeded . The API uses request/event objects ( onsuccess / onerror ), so people wrap each request in a Promise to use async/await .
Quick Reference — One Line Each
API
Signature
Keep all results
await Promise.allSettled(promises)
Stream values
for await (const x of gen())
Cancel
fetch(url, { signal: c.signal })
Background work
worker.postMessage(data)
Visibility
observer.observe(el)
Store data
db.transaction("s", "readwrite")
Draw
ctx.fillRect(x, y, w, h)
📚 Keep Learning
- • MDN — Web APIs index
- • MDN — Using promises
- • MDN — Progressive Web Apps (where these combine)
Frequently Asked Questions
🎉 Checkpoint Complete — Browser APIs!
- ✅ Recapped combinators, async iterators, AbortController, workers, observers, IndexedDB, and canvas
- ✅ Built a resilient pipeline: fan-out fetch + async generator + cache
- ✅ Reviewed the full solution and tested your recall with the quiz
- ✅ You can now fetch, stream, cancel, cache, and render real data
Up next: Final Project — put all of it to work. 🚀
Practice quiz
You fetch five widgets and want to show whichever ones load, even if some fail. Which combinator?
- Promise.all
- Promise.race
- Promise.allSettled
- Promise.any
Answer: Promise.allSettled. allSettled never rejects and returns a result object per promise, so you keep successes and count failures.
How does Promise.all behave when one of its promises rejects?
- It rejects immediately (fail-fast)
- It ignores the rejection
- It returns the partial results
- It retries the failed one
Answer: It rejects immediately (fail-fast). Promise.all is fail-fast: the first rejection rejects the whole thing.
What does Promise.race resolve to?
- The first successful result only
- All results in order
- The slowest result
- The result of whichever promise settles first
Answer: The result of whichever promise settles first. race settles with the first promise to settle, whether it fulfils or rejects.
What does Promise.any resolve to?
- The first promise to settle
- The first promise to fulfil (ignoring rejections)
- All fulfilled values
- The last rejection
Answer: The first promise to fulfil (ignoring rejections). any resolves with the first fulfilment and only rejects if every promise rejects.
What loop consumes an async function*, and what must surround it?
- for await...of, inside an async function
- for-of, inside any function
- while, inside a generator
- forEach, with await inside
Answer: for await...of, inside an async function. for await...of consumes async iterables and must live inside an async function.
After controller.abort(), what happens to an in-flight fetch using that signal?
- It resolves with empty data
- It silently completes
- Its promise rejects with an AbortError
- It retries automatically
Answer: Its promise rejects with an AbortError. The fetch rejects with a DOMException named AbortError; check err.name to ignore deliberate cancellations.
Why can't you pass a function to worker.postMessage()?
- Functions are too large
- Messages are structured-cloned, which can't clone functions
- Workers only accept strings
- It would create a security hole
Answer: Messages are structured-cloned, which can't clone functions. The structured clone algorithm cannot copy functions or DOM nodes — it throws a DataCloneError.
Which option lets IntersectionObserver lazy-load images shortly BEFORE they scroll into view?
- threshold
- delay
- once
- rootMargin
Answer: rootMargin. A positive rootMargin expands the viewport box so elements count as visible early.
Where must IndexedDB object stores be created?
- In onsuccess
- Inside the onupgradeneeded handler
- Anywhere after open()
- In a transaction's oncomplete
Answer: Inside the onupgradeneeded handler. Object stores and indexes can only be created during the onupgradeneeded event.
On the Canvas 2D context, where is the coordinate origin and what unit do arcs use?
- Center origin, degrees
- Bottom-left origin, radians
- Top-left origin, radians
- Top-left origin, degrees
Answer: Top-left origin, radians. Canvas places (0,0) at the top-left and arc angles are measured in radians.
Continue this course
- Previous: The Canvas API
- Next: Final Project