The rendering pipeline

HTML parsing is incremental

Understand how the parser builds the DOM as bytes arrive and why some scripts can pause that process.

The browser does not wait for the whole HTML response before it starts building the DOM.

Bytes come in over the network in chunks. The browser decodes each chunk, splits it into tokens, and creates nodes right away. By the time the last byte arrives, most of the tree already exists. This is what lets resource discovery and rendering start while HTML is still downloading.

You can see it on a slow connection. The header of a page appears while the footer is still on its way.

Scripts can pause the parser

A classic script stops this flow:

<script src="/app.js"></script>

When the parser reaches this tag it has to stop. The script might call document.write() and inject markup right here. It might read the DOM as it exists at this exact point. The browser can’t know, so it fetches the script, runs it, and only then continues parsing.

On a slow network that pause is visible. Everything after the script waits.

defer and async

defer fixes this for external scripts. The download starts right away, in parallel with parsing, and the script runs after the document is fully parsed, in document order.

async also downloads in parallel, but it runs as soon as it arrives, pausing the parser at that moment. Several async scripts run in whatever order they finish, not the order in the markup.

We covered the trade-offs in the async and defer lesson. The short version: use defer unless you have a reason not to.

Watch the pause

Open the Network panel and set throttling to “Slow 3G”. Load a page with a blocking script in the middle of the body, then the same page with defer on that script.

In the Performance panel, look at the Parse HTML entries on the Main track. With the blocking script you’ll see parsing stop, a gap while the script downloads and runs, then parsing resume. With defer the parse runs in one go and DOMContentLoaded fires earlier.

Try this on your own project: put a visible paragraph before and after a slow classic script. Delay the script by a couple of seconds on the server and watch when each paragraph shows up. The first one appears immediately. The second waits for the script.

Lesson completed