• Inside Look at Modern Web Browser (Part 3)
  • Originally written by Mariko Kosaka
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: ssshooter
  • Proofread by ThomasWhyne, CoolRice

The internal mechanics of the renderer process

This is the third in a four-part blog series on how browsers work. Earlier, we introduced multi-process architecture and navigation flows. In this article, we’ll take a look at the inner workings of the rendering process.

The renderer process involves many aspects of Web performance. Because the process of rendering is too complex, this article only gives an overview. If you want to take a closer look, check out the Performance Section of Web Fundamentals.

The rendering process processes the web site content

The renderer is responsible for everything that happens inside the TAB. In the renderer process, the main thread handles most of the code that the server sends to the user. If you use a Web worker or service worker, part of the JavaScript will be handled by the worker thread. Composition and raster threads also run within the render process to render the page efficiently and smoothly.

The core job of the rendering process is to transform HTML, CSS, and JavaScript into a web page that users can interact with.

Figure 1: The renderer process contains the main thread, worker thread, composite thread, and raster thread

Parsing

The construction of the DOM

When the renderer process receives the submission message for the navigation and begins to receive THE HTML data, the main thread begins to parse the text string (HTML) and convert it into the Document Object model (DOM).

The DOM is the internal representation of a page in a browser and a data structure and API that Web developers can interact with through JavaScript.

HTML to DOM parsing is specified by the HTML Standard. You may have noticed that the process of feeding HTML to the browser never raises an error. Like a Hi! I’m Chrome! An error such as
will be interpreted as Hi! I’m Chrome!
, because the HTML specification handles these errors gracefully. If you’re curious about how this is done, read the HTML specification section of An Introduction to Error Handling and Strange Cases in the Parser.

Subresource loading

Websites often use external resources such as images, CSS, and JavaScript that need to be loaded from the web or cache. As the DOM is parsed and built, the main thread requests them one by one in the order in which they are processed, but for speed, the preload scanner runs simultaneously. If there is something like < IMG > or in the HTML document, the preload scanner looks at the markup generated by the HTML parser and sends a request to the network thread in the browser process.

Figure 2: The main thread parses the HTML and builds the DOM tree

JavaScript blocking parsing

When the HTML parser encounters a

Prompt browser how to load resources

Web developers can send prompts to browsers in a number of ways to load resources properly. If your JavaScript doesn’t use Document.write (), you can add async or defer properties to the

Style calculation

Having the DOM alone is not enough to determine the appearance of the page, because we style the page elements in CSS. The main thread parses the CSS and determines the computed style of each DOM node. This is information about what style to apply to each element based on CSS selectors, as you can see in the Computed section of DevTools.

Figure 3: The main thread parses the CSS to add the computed style

Even if you don’t provide any CSS, every DOM node has a computational style. Tags like

look larger than < H2 > tags, and each element has a margin because browsers have default stylesheets. If you want to know more about Chrome’s default CSS, you can see the source code here.

layout

Now, the rendering process knows the style of each node and the structure of the document, but this is not enough to render the page. Imagine trying to describe a painting to a friend on your mobile phone: “Here’s a big red circle and a small blue square.” That doesn’t tell your friend what the painting actually looks like.

Figure 4: A person standing in front of a painting, telephone lines connected to another person

Layout is the process of calculating the geometry of elements. The main thread traverses the DOM, calculating the style and creating a layout tree that contains information such as x and Y coordinates and bounding box sizes. A layout tree may be similar to a DOM tree structure, but it contains only information related to what is visible on the page. If display: None is applied to an element, it is not part of the layout tree (but the element visibility: Hidden is in the layout tree). Similarly, if an application such as p::before{content:”Hi!” } is included in the layout tree even if it is not in the DOM.

Figure 5: The main thread traverses the DOM tree after the computed style to generate the layout tree

Figure 6: Box layout moved due to line breaks

Determining the layout of a page can be a challenging task. Even the simplest page layout, such as a top-to-bottom block flow, must take into account the size of the font and the position of the newline, which can affect the size and shape of the paragraph and thus the position of the next paragraph.

CSS can float elements to one side, hide overflow elements, and change the direction of writing. You can imagine the magnitude of the task at this stage. Chrome has a whole team of engineers responsible for the layout. Some of the interviews at the BlinkOn conference recorded the details of their work, which would be interesting to learn about.

draw

Figure 7: A person stands in front of a canvas with a pen, wondering whether she should draw circles or squares first

Having DOM, style, and layout is still not enough to render a page. Suppose you’re trying to recreate a painting. You know the size, shape, and position of the elements, but you still need to determine the order in which to draw them.

For example, you can set z-index for some elements, where drawing in the order of the elements written in HTML will result in incorrect rendering.

Figure 8: Because z-index is not taken into account, page elements appear in the order of HTML tags, resulting in incorrectly rendered images

In the draw step, the main thread traverses the layout tree to create the draw record. The drawing record is a record of the drawing process, as in “background first, then text, then rectangle”. If you’ve ever used JavaScript to draw a

element, this process will probably be familiar to you.

Figure 9: The main thread traverses the layout tree and generates draw records

The cost of updating the render pipeline is high

Figure 10: DOM + Style, layout, and drawing tree generation order

The most important thing in the rendering pipeline is that in each step, the results of the previous operation are used to create new data for the next operation. For example, if something in the layout tree changes, the “Draw” command needs to be regenerated for the affected part of the document.

If you want to animate an element, the browser must run these operations between each frame. Most monitors refresh the screen 60 times per second (60 FPS), and when the screen changes every frame, the animation feels smooth to the human eye. However, if the animation misses some intermediate frames, the page will look stuck (Janky).

Figure 11: Animation frames on the timeline

Even if the render operation keeps up with the screen refresh, these calculations will run on the main thread, which means the animation may block when your application runs JavaScript.

Figure 12: Animation frame on timeline, but JavaScript blocks one frame

You can break up JavaScript operations into small chunks and run them on each frame using requestAnimationFrame(). For more information on this topic, see Optimize JavaScript Execution. You can also run JavaScript in the Web Worker to avoid blocking the main thread.

Figure 13: The smaller JavaScript block on the timeline runs with the animation frame

synthetic

How to draw a page?

Figure 14: Schematic animation of simple raster processing

Now that the browser knows the structure of the document, the style of each element, the geometry of the page, and the order in which it draws the page, how does it draw the page? Converting this information into pixels on the screen is called rasterization.

A simple way to handle this situation is to start with the screen in the raster window, and if the user scrolls the page, move the raster frame and raster the missing parts. This is how Chrome handled rasterization when it was first released. However, modern browsers run a more complex process called compositing.

What is composition

Figure 15: Composite processing schematic animation

Composition is a technique for layering parts of a page, rasterizing them separately, and composing them into pages in separate threads called composition threads. If scrolling happens, all it has to do is compose a new frame, since the layer is rasterized. Animations can be done in the same way (moving layers and compositing new frames).

You can use the Layers panel in DevTools to see how your site is layered.

layered

To figure out which elements are on which layers, the main thread traverses the layout Tree to create a Layer Tree (called the “Update Layer Tree” in the DevTools performance panel). If parts of the page should be separate layers (such as slide-in side menus) but are not split out, you can use the will-change property in CSS to alert the browser.

Figure 16: The main thread traverses the layout tree to generate the layer tree

You may want to layer each element, but composing a large number of layers can be slower than rasterizing the page every frame, so measuring your application’s rendering performance is critical. For more information on this topic, see Stick to Compositor-only Properties and Manage Layer Count.

Rasterization and synthesis of the main thread

Once the layer tree is created and the drawing order determined, the main thread submits this information to the composition thread. Next, the composition thread rasterizes each layer. A layer can be as large as the entire page, so the composition thread blocks them and sends them to the raster thread. The raster thread rasterizes each chunk and stores it in video memory.

Figure 17: Raster threads create partitioned bitmaps and send them to the GPU

The composite thread sets priority to the different raster threads so that the frames in the window (or nearby) can be rasterized first. The layer also has multiple blocks of different resolutions that can handle actions such as zoom operations.

Once the blocks are rasterized, the composition thread collects information about those blocks (called drawing quadrilateral) to create a composition frame.

Draw a quadrilateral

Contains information such as the location of the block in memory and the location of the block in the page when drawing when compositing.

Synthesis of frame

A collection of drawn quadrangles representing a frame on a page.

The composite frame is then submitted to the browser process via IPC (interprocess communication). At this point, another composited frame can be added from the UI thread or the renderer process of another plug-in. These synthesizer frames are sent to the GPU and displayed on the screen. If a scroll event is received, the compositing thread creates another compositing frame to send to the GPU.

Figure 18: The compositing thread creates a compositing frame, sends it to the browser process, and then sends it to the GPU

The advantage of composition is that it can be done without involving the main thread. The composite thread does not need to wait for style calculations or JavaScript execution. This is why composit-only animation is considered the best choice for fluency. If you need to evaluate the layout or draw again, you must refer to the main thread.

conclusion

In this article, we’ve explored the entire rendering pipeline from parsing to compositing, and hope you’re now free to learn more about optimizing your site’s performance.

In the next and final article in this series, we’ll look at synthetic threads in more detail and see what happens when the user moves or clicks the mouse.

Did you enjoy this article? If you have any questions or suggestions for future articles, I’d be happy to contact you in the comments section below or on Twitter @kosamari.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.