When does parsing HTML DOM tree happen?

TL;DR: Parsing starts instantaneously after receiving the document.

Parsing and painting

For a more detailed explanation, we need to dive into the way rendering engines work.

Rendering engines parse the HTML document and create two trees: the content tree and the render tree. A content tree contains all DOM nodes. The render tree contains all styling information (the CSSOM) and only the DOM nodes that are required to render te page.

As soon as the render tree has been created, the browsers goes through two processes: applying layout and painting each DOM node. Applying layout means calculating the exact coordinates where a DOM node should appear on the screen. Painting means actually rendering the pixels and applying stylistic properties.

This is a gradual process: browsers won't wait until all HTML is parsed. Parts of the content will be parsed and displayed, while the process continues with the rest of the contents that keeps coming from the network.

You can see this process happening in your browser. For example, open the Chrome Developer Tools and load a site of your choice.

Network tab

After recording activity in the Network tab, you'll notice that parsing starts while downloading the document. It recognises resources and starts downloading them. The blue vertical line indicates the DOMContentLoaded event and the red vertical line indicates the load event.

Timeline tab

Recording a timeline gives you much more insight in what happens under the hood. I have included the screenshot above as an example to indicate that painting happens while parsing the document. Note that the initial paint occurs just before it continues parsing another part of the document. This process continues until it reaches the end of the document.

Single threaded

The rendering engine is single threaded. Almost everything, except network operations, happens in this thread.

Combine that with the synchronous nature of the web. Developers expect <script>'s to be parsed and executed immediately (that is: as soon as the parser reaches a script tag). That means that:

  1. The resource must be fetched from the network (this might be a slow process due to DNS lookups and speed of connection).
  2. The content of the resource is passed to the Javascript interpreter.
  3. The interpreter parses and executes the code.

Parsing the document halts until this process finishes. You don't improve the total parsing time by including <script>'s at the end of the document. It does enhance the user experience, as the process of parsing and painting isn't interrupted by <script>'s that need to be executed.

It is possible to work around this issue by marking the resource with defer and / or async. async downloads the file during HTML parsing and will pause the HTML parser to execute it when it has finished downloading. defer downloads the file during HTML parsing and will only execute it after the parser has completed.

Speculative parsing

Some browsers aim to work around the blocking aspect of <script>'s by using so called speculative parsing. The engine parses ahead (and runs the HTML tree construction!) while scripts are being downloaded and executed. Firefox and Chrome use this technique.

You can imagine the performance gain if a speculation succeeds (eg. the DOM wasn't altered by the scripts that are included in the document). Waiting for the scripts to execute wasn't necessary and the page has been painted successfully. The downside is that there's more work lost when the speculation fails.

Luckily for us, very smart people work at these technologies, so even using document.write properly won't break this process. Another rule of thumb is not to use document.write. For example, it could break the speculative tree:

// Results in an unbalanced tree
<script>document.write("<div>");</script>

// Results in an unfinished token
<script>document.write("<div></div");</script>

Further reading

The following resources are worth your time reading:

  • Web Fundamentals (Google Developers)
  • How browsers work
  • MDN on HTML5 Parser
  • An introduction to Browser Rendering (video)

This is actually dependent on the browser as to the specific order that everything is loaded but for DOM parsing it works top to bottom. The parser moves branch by branch, so when it encounters the head, it will move through each child. If an element has a child it will then move onto the child/children before moving back up the tree. To put that in very basic pseudo-code:

while DOM != parsed:
    if current_node.has_child():
        current_node = child_node
        execute_node()
    elif current_node.has_sibling():
        current_node = sibling_node
        execute_node()
    elif current_node.has_parent_sibling():
        current_node = parent_sibling
        execute_node()
    else:
        current_node = parent_node

It essentially deals with script/link tags as parent nodes, initiate a HTTP/S GET Request if it's an external file and parse the code before moving on to the next node. So the reason we use put script tags at the end is because they usually aren't used at page load, but handle things after it is loaded. So the consensus is that it's better to get something on the page then load your JS later so that it can handle that oh so important animation you have on a menu item.

There are of course exception to this, whereby you can specify to the DOM parser to execute scripts asynchronously - the parser creates an extra thread to parse the JS - or defer - GET Request is made but the file is not parsed until the HTML Document is finished parsing.


Another saying is, putting <script> in the end of <body> is the best practice so that the page renders something before script is downloaded.

The major reason of putting script tag to the end of body tag is: download and execute JavaScripts will block HTML parsing (or, you can say they are just parts of parsing). If they are put in the <head>, the user may wait for a long time before he could see anything on web page. Image you have a html page like this:

<html>
  <head>
    <!-- this huge.js takes 10 seconds to download -->
    <script src="huge.js"></script>
  </head>
  <body>
    <div>
      My most fancy div!
    </div>
  </body>
</html>

// huge.js
(function () {
   // Some CPU intensive JS operations which take 10 second to complete
})();

The browser will start to execute those CPU-intensive JS right after it reaches that <script> tag. And it will block parsing the rest of the HTML content. So in this case, the user won't be able to see his fancy div before that JavaScript is downloaded and executed (takes 20 seconds in total).

You can use DOMContentLoaded to detect whether the initial DOM is loaded and parsed. And your statement in last paragraph is quite correct: every time HTML parser see a <script>, it will download and execute it synchronously (see Notice 2). After all <script> are executed and all HTML is parsed, DOMContentLoaded will be fired.

Notice 1: DOMContentLoaded will NOT wait for CSS and images

Notice 2: Most browsers have "Speculative parsing" feature. If there are multiple JavaScript files, they will be downloaded simultaneous. However, they will still be executed sequential by the main thread.

For your last question:

Or, does the page paints the page at the same time of parsing DOM tree?

From my own understanding, the answer is YES, the browser will try to paint ASAP. That is to say, the paint engine won't wait for render tree is fully ready. So there should be a separated thread to handle the paint.

Feel free to correct me if any of my understanding is wrong :)

References:

  1. https://www.chromium.org/developers/the-rendering-critical-path
  2. http://taligarsiel.com/Projects/howbrowserswork1.htm