AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

12 The DOM and the browser / Checkpoint

Checkpoint — The DOM and the browser

24 min · +25 XP · 3 exercises · 12 questions

Exercises0/3
Quiz · 70% to clear12 q

This checkpoint covers the DOM tree and selection, attributes versus properties, textContent versus innerHTML, batching and reflow; event propagation, target/currentTarget, delegation, preventDefault/stopPropagation, custom events; fetch semantics, URL/URLSearchParams, timeouts with AbortController, CORS; Web Storage, cookies and their attributes, the History API, observers and workers; the rendering pipeline, loading path, vitals, and the XSS/CSRF defences.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module. The programs model browser mechanisms in Node — a DOM tree, an event dispatcher, a router — because the judge has no browser; the ideas are exactly the browser's.

Before you start, make sure you can answer:

  • Attribute versus property for value; which content API is safe for user data; why getElementsByClassName bites when removing.
  • The three phases; what closest does in a delegated handler; why stopPropagation is usually a smell; passive.
  • Why a 404 does not reject; how to time out a fetch; what a CORS error means and who fixes it.
  • The three cookie flags and what each defends; pushState versus popstate; when to use IndexedDB.
  • Which CSS properties skip layout; defer versus async; the layered XSS defences; the CSRF defence.

The programs are a virtual-DOM differ that emits a minimal patch list, a client-side router with parameterised routes and a history stack, and a stale-while-revalidate fetch cache modelled with timers.

Common questions

Why does getElementsByClassName skip elements when you remove them in a loop?

It returns a live HTMLCollection that updates as the DOM changes. Removing the element at index 0 shifts the next one into index 0 while the loop moves on to index 1, so every other element is skipped. Loop over a static querySelectorAll result, or copy the collection into an array first.

What does closest do in a delegated event handler?

e.target.closest(selector) walks up from the element the event landed on, perhaps an icon inside a button, to the nearest ancestor, or the element itself, that matches the selector. In a delegated listener it finds the item that was actually clicked, and returns null when the click fell between items.

Why is stopPropagation usually a code smell?

Stopping propagation to keep an outer handler from running couples the two handlers invisibly: analytics, a "click outside to close" handler or a delegated listener higher up silently never sees the event. Let events bubble and have the outer handler check e.target instead, for example returning early when the dialog contains it.

DOM and Browser APIs Quiz: Events, Fetch and CORS Practice

Test your browser JavaScript with 12 questions and three programs on the DOM, event propagation, fetch and CORS, cookies and storage, rendering, XSS and CSRF.

  • Course: JavaScript study plan
  • Module: The DOM and the browser
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 24 min
  • Runtime: Node 16

Checkpoint — The DOM and the browser is the checkpoint that closes the The DOM and the browser module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers the DOM tree and selection, attributes versus properties, textContent versus innerHTML, batching and reflow; event propagation, target/currentTarget, delegation, preventDefault/stopPropagation, custom events; fetch semantics, URL/URLSearchParams, timeouts with AbortController, CORS; Web Storage, cookies and their attributes, the History API, observers and workers; the rendering pipeline, loading path, vitals, and the XSS/CSRF defences.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module. The programs model browser mechanisms in Node — a DOM tree, an event dispatcher, a router — because the judge has no browser; the ideas are exactly the browser's.

Before you start, make sure you can answer:

  • Attribute versus property for value; which content API is safe for user data; why getElementsByClassName bites when removing.
  • The three phases; what closest does in a delegated handler; why stopPropagation is usually a smell; passive.
  • Why a 404 does not reject; how to time out a fetch; what a CORS error means and who fixes it.
  • The three cookie flags and what each defends; pushState versus popstate; when to use IndexedDB.
  • Which CSS properties skip layout; defer versus async; the layered XSS defences; the CSRF defence.

The programs are a virtual-DOM differ that emits a minimal patch list, a client-side router with parameterised routes and a history stack, and a stale-while-revalidate fetch cache modelled with timers.

Common questions

Why does getElementsByClassName skip elements when you remove them in a loop?

It returns a live HTMLCollection that updates as the DOM changes. Removing the element at index 0 shifts the next one into index 0 while the loop moves on to index 1, so every other element is skipped. Loop over a static querySelectorAll result, or copy the collection into an array first.

What does closest do in a delegated event handler?

e.target.closest(selector) walks up from the element the event landed on, perhaps an icon inside a button, to the nearest ancestor, or the element itself, that matches the selector. In a delegated listener it finds the item that was actually clicked, and returns null when the click fell between items.

Why is stopPropagation usually a code smell?

Stopping propagation to keep an outer handler from running couples the two handlers invisibly: analytics, a "click outside to close" handler or a delegated listener higher up silently never sees the event. Let events bubble and have the outer handler check e.target instead, for example returning early when the dialog contains it.

Exercises

A virtual-DOM differ

Two lines hold JSON trees: { tag, props, children } where a child is a tree or a string. Write diff(a, b, path, patches) producing, in document order: REPLACE <path> when a text node and an element swap, REPLACE <path> <oldTag> -> <newTag> for different tags (do not descend), TEXT <path> <oldJSON> -> <newJSON>, PROPS <path> <+k=v ~k=v -k …> (added in new-key order, then changed, then removed), and for children by index INSERT <path> <"text" or <tag>> / REMOVE <path>; paths are root, root/0, root/1/0. Print the patches one per line or no changes.

Example: a list whose class and role change, whose first item loses an id, whose second item's text changes, and which gains a fourth item →

PROPS root ~class="list active" +role="list"
PROPS root/0 -id
TEXT root/1/0 "Ink" -> "Blue Ink"
INSERT root/3 <li>

A client-side router with a history stack

Lines route <pattern> declare routes with :param segments and a trailing * (captured as rest); compile each to a regex. Keep a history array starting at ["/"] with an index. Commands: push <path?query> (discard the forward stack, append, move) prints pushState <path> -> <match>; replace <path> prints replaceState …; back/forward move the index and print popstate <path> -> <match> (or back: nothing to go back to / forward: nothing ahead); stack prints stack=<JSON> index=<n>. A match is matched <pattern> params=<JSON> query=<JSON of the query string> (first declared route wins) or 404 <pathname>.

Example (excerpt):

pushState /users/42?tab=posts -> matched /users/:id params={"id":"42"} query={"tab":"posts"}
pushState /files/docs/a.pdf -> matched /files/* params={"rest":"docs/a.pdf"} query={}
popstate /users/42/posts/7 -> matched /users/:id/posts/:postId params={"id":"42","postId":"7"} query={}
pushState /nowhere -> 404 /nowhere

A push after going back drops the entries ahead — exactly what the browser does.

A stale-while-revalidate cache

fetchValue(key) (in the starter) takes 10 ms, counts calls and returns <key>#<count>. Implement SwrCache(ttlMs).get(key): on a miss fetch, store with a timestamp and return { status: "miss", value }; when the entry is younger than the TTL return { status: "hit", value }; when it is stale return the stale value immediately as { status: "stale", value } and start one background revalidation that replaces the entry when it completes (a second stale read while it is in flight must not start another). Line 1 is the TTL; commands get <key> print get <key>: <status> <value> fetches=<count> and wait <ms> prints (waited <ms> ms).

Example: TTL 40, then get a, get a, wait 60, get a, get a, wait 20, get a, get b →

get a: miss a#1 fetches=1
get a: hit a#1 fetches=1
  (waited 60 ms)
get a: stale a#1 fetches=2
get a: stale a#1 fetches=2
  (waited 20 ms)
get a: hit a#2 fetches=2
get b: miss b#3 fetches=3

The stale reads answered instantly with the old value while one refresh ran; the next read after it landed was fresh.

In this module: The DOM and the browser

← Rendering performance and front-end security — the two things a page must not get wrong · What TypeScript adds — erased types, inference, and any versus unknown versus never →