Browser rendering and performance

In order to deliver one web page, a ton of hard work needs to be done in the browser. As developers having a good understanding of how the browser works gives us insights into how to optimize performance. Here are some study notes I took. Hats off to browser developers!!!

The rendering a webpage in the browser can be broken down into 4 steps:

1. Parsing:

HTML and CSS are parsed to construct parse trees, which will be turned into DOM trees.

HTML is forgiving syntax-wise for better browsing experiences. Even if tags are not closed the browser will recognize tags and construct a parse structure tree with all tags. This is done through the tokenizer, which recognizes symbol characters as special things like a “start tag”.

Things like <script>, <link> and <style> JavaScript/CSS specified in HTML can halt the parser from continuing to parse the rest of the HTML.

Performance insight: But because modern browsers will look for these tags, fetch and process any external scripts, images and stylesheets in a multi-threaded manner, it’s considered best practice to always include JavaScript and CSS externally. There is an exception for CSS, though. Since inline CSS has the highest priority, inline CSS will always be parsed prior to other CSS. One can use this property to improve the speed of CSS parsing/rendering.

If JavaScript changes the DOM structure, such as adding an element, HTML needs to be re-parsed and that takes more time.

2. Form Render Object tree:

This maps the respective nodes, styles of the nodes, and boxes of elements in the DOM.

3. Layout:

Once browser gets the render tree it starts constructing the layout according to this tree. It will traverse each render object recursively, laying out children first, and then parent elements.

If the user interacts with the page and cause changes, browser will detect changes and apply in batches. But if the changes are large-scale, for example, font changes and browser resizing, the layout will have to be reconstructed and that slows down rendering a lot.

Performance insight: The JavaScript best practice is to batch all reads and all writes separately to avoid having to re-layout a lot of things every step of the way.

4. Painting:

RenderLayers is constructed from RenderObject. It produces layers to correctly display the position, transparency, etc. of the nodes. There can be multiple nodes on the same layer depending on their CSS properties.

Performance insight: The browser will utilize the GPU to produce bitmaps of each layer to be displayed on the user’s screen.

Similar to scalable temporal video coding, the problem of re-layout delay can be solved by “delta last bitmap”, comparing last to current bitmaps so that it only needs to re-draw a small portion of the page.

The rendering process is a constantly ongoing loop, since the user will constantly be interacting with the page in session. There are also a lot of tips and tricks as to how to optimize browsing experience, such as using fixed height, delaying/asyncing scripts and stylesheets to speed up first paint, etc.