Rendering · stage 04
Parsing before the download ends
The HTML parser does not wait. It processes bytes as they arrive, building the DOM one node at a time — which is why what you put in the document, and where, changes everything.
Stage 04 of six/Rendering, piece 3 of 3/Short piece/Next: Specificity
The stream is the input
When a browser receives an HTML response, it hands the incoming bytes directly to the tokeniser. No buffering until the end, no batch parse — the tree grows as the network delivers. This incremental model is why a large page can begin rendering before the final byte lands, and why <h1> tags appear on screen while the footer is still in transit.
The parser runs in a single pass, emitting nodes into the DOM as each tag closes. Block elements start being laid out, text is measured, paint begins — all before the </html> tag exists. That pipeline depends on one assumption: that the rules governing the layout are already known. When they are not, everything stops.
A <script> tag without async or defer is a hard stop. The parser halts, waits for the script to be fetched if it is external, then executes it synchronously, because the script may call document.write or alter the DOM in ways that would invalidate anything parsed after it. This is not a browser quirk — it is specified behaviour in the WHATWG HTML Living Standard. The consequence is concrete: a render-blocking script in <head> delays the first visible content by the full round-trip time of that fetch.
CSS is different in kind but equally blocking. A stylesheet does not pause the parser itself, but it blocks rendering: the browser will not composite a frame while stylesheets are still loading, because painting before the rules arrive would mean painting incorrectly. Gecko, Blink and WebKit all share this constraint, however differently they schedule network requests internally.
Modern engines paper over the worst cases with a speculative or preload scanner — a lightweight second pass that looks ahead in the raw byte stream, queuing <script> and <link> fetches before the main parser reaches them. The main parser still stalls at the script tag; it just finds the file already cached when it arrives.
The document order is therefore load-order policy. Position determines what blocks what.
This is not a browser quirk — it is specified behaviour in the WHATWG HTML Living Standard.