Execution — bi-04-dom-internals

Steps extracted from CONCEPTS.md. Read the concepts first; this file is the doing.

Record results in observation.md; tick checkpoints in verification.md.


Lab

mini-browser M3 — a real DOM.

  1. Node, Element, Text, Document; parent/child/sibling links.
  2. appendChild, insertBefore, removeChild, remove with correct ordering and hierarchy checks (including: appending a node that already has a parent removes it first; appending an ancestor to its own descendant must throw).
  3. Attributes with a separate reflected-property layer for at least class and id.
  4. A dirty-marking scheme: mutations mark nodes, and nothing is recomputed until a flush().
  5. MutationObserver-alike with microtask-queued delivery.
  6. A deliberate second implementation of dirty-marking: naive (recompute everything) vs scoped. Measure both on a 10,000-node tree.

Deliverable: a table showing operations/second for both schemes, and a written explanation of where the crossover is and why.


Failure Lab

  1. Forced synchronous layout. Write a loop that writes then reads geometry each iteration. Measure. Then batch reads and writes. Explain the complexity change, not just the wall clock.
  2. The detached-subtree leak. Build one deliberately. Find it in DevTools' heap snapshot. Then find the retaining path — the skill is reading the retainer chain, not noticing the growth.
  3. Observer storm. Attach a MutationObserver that mutates the DOM in response to mutations. Predict the outcome before running: infinite loop, or something subtler? Explain in terms of the microtask checkpoint.
  4. Property/attribute divergence. Build a form where setting the attribute after user input does nothing visible. Explain to a hypothetical junior engineer in three sentences.

Debugging Exercise

  1. Breakpoint on the container-node insertion path. From document.body.appendChild(el) in the console, capture the full stack: how many frames between the binding and the actual pointer update?
  2. Find the Trace() method of an Element. List what it keeps alive. Predict what happens to a listener closure when the element is removed but a JS reference is retained — then verify with a heap snapshot.
  3. Use tracing to observe that a batch of DOM mutations produces exactly one style recalc. Then insert a geometry read into the loop and observe the change.