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.
Node,Element,Text,Document; parent/child/sibling links.appendChild,insertBefore,removeChild,removewith 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).- Attributes with a separate reflected-property layer for at least
classandid. - A dirty-marking scheme: mutations mark nodes, and nothing is recomputed until a
flush(). MutationObserver-alike with microtask-queued delivery.- 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
- 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.
- 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.
- Observer storm. Attach a
MutationObserverthat mutates the DOM in response to mutations. Predict the outcome before running: infinite loop, or something subtler? Explain in terms of the microtask checkpoint. - 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
- 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? - Find the
Trace()method of anElement. 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. - 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.