The original linkDevelopers.google.com/web/updates…
The inner workings of the renderer process
This is the third article in a series on how browsers work. Earlier, we introduced multi-process architecture and navigation flows. In this article, we’ll look at what happens inside the renderer process.
The renderer process involves many aspects of Web performance. Due to a lot of things happening inside the renderer process, this article is just a general overview. If you want to dig deeper, Why does Speed matter? More resources are available in the performance section.
The renderer process processes Web content
The renderer process is responsible for everything that happens inside the TAB. In the renderer process, the main thread handles most of the code you send to the user. If you use a Web Worker or Service Worker, sometimes part of the JavaScript is processed by the Worker thread. To render the page efficiently and smoothly, the synthesizer and raster threads also run in the renderer process.
The core job of the renderer process is to transform HTML, CSS, and JavaScript into web pages that users can interact with.
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 browser’s internal representation of a page, as well as a data structure and API that Web developers can interact with through JavaScript.
Parsing HTML documents into the DOM is defined by the HTML standard. You may have noticed that serving HTML to a browser never raises an error. For example: Missing the closing
tag is valid HTML, like Hi! I’m Chrome!
(the B tag closes before the I tag) The error tag is treated as if you wrote Hi! I’m Chrome!
, because the HTML specification is designed to handle these errors gracefully. If you’re curious about how these things are done, you can read the HTML specification’s An Introduction to Error Handling and Strange Cases in the Parser section.
Subresource loading
Websites often use external resources such as images, CSS, and JavaScript. These files need to be loaded from the network or cache. The main thread can request each of these as it finds them during parsing and building the DOM, but to speed things up, the “preload scanner” runs simultaneously. If there is something like < IMG > or in the HTML document, the preload scanner looks at tokens generated by the HTML parser and sends the request to the web thread in the browser process.
JavaScript prevents parsing
When the HTML parser finds the
Prompt browser how do you want to load resources
Web developers can send prompts to browsers in a number of ways to load resources nicely. If your JavaScript doesn’t use Document.write (), you can add async or defer properties to the
Style calculation
Having the DOM is not enough to know what the page will look like, because we can style the page elements in CSS. The main thread parses the CSS and determines the style of each DOM node. This is information about which style is applied to each element based on the CSS selector. You can see this information in the computing section of DevTools.
Even if you don’t provide any CSS, every DOM node has a computed style. The < H1 > tag is displayed larger than the < H2 > tag, and margins are defined for each element. This is because the browser has a default style sheet. If you want to know what Chrome’s default CSS looks like, you can check out the source code here.
layout
Now the renderer process knows the structure of the document and the style of each node, but this is not enough to render the page. Imagine that you are trying to describe a painting to your friend over the phone. “There is a big red circle and a small blue square” is not enough to let your friend know what the painting really looks like.
Layout is a process of finding the geometry of elements. The main thread traverses the DOM and evaluates styles, and creates a layout tree that contains information such as xy coordinates and bounding box sizes. A layout tree may have a similar structure to a DOM tree, but it contains only information related to what is visible on the page. If display: None is used, the element is not part of the layout tree (however, an element with visibility: hidden is in the layout tree). If you use something like p::before{content:”Hi!” }, which is included in the layout tree even if it is not in the DOM.
Determining the layout of a page can be a challenging task. For even the simplest page layout, such as a top-to-bottom block flow, you have to consider how big the font is and where the line breaks, because these affect the size and shape of paragraphs; This affects where the next paragraph needs to be.
CSS allows elements to float to one side, shielding overflow items, and changing the direction of writing. It is conceivable that this layout phase task is arduous. In Chrome, a team of engineers is responsible for layout. If you want to check out the details of their work, some of the presentations at the BlinkOn Conference were recorded and very interesting.
draw
Having DOM, style, and layout is still not enough to render a page. Suppose you are trying to copy a painting. You know the size, shape and position of the elements, but you still need to judge the order in which you draw them.
For example, you might set z-index for some elements, in which case drawing in the order of the elements written in HTML would result in incorrect rendering.
In this draw step, the main thread traverses the layout tree to create the draw record. Painting record is a record of the painting process of “background first, then text, and then rectangle”. If you use JavaScript to draw on a
Updating the render pipeline is expensive
One of the most important aspects of the rendering pipeline is that at each step, new data is created using the results of the previous operation. For example, if something in the layout tree changes, you need to regenerate the drawing order for the affected portions of the document.
If you are animating elements, the browser must run these actions between each frame. Most of our monitors refresh the screen 60 times per second (60 FPS); As you move objects on the screen in each frame, the animation appears smooth to the human eye. However, if the animation misses the middle frame, the page will appear “Janky.”
Even if your render operation keeps up with the screen refresh, these calculations run on the main thread, which means that when your application runs JavaScript, it may be blocked.
You can break JavaScript operations into small chunks and schedule them to run on each frame using requestAnimationFrame(). For more information on this topic, see Optimize JavaScript Execution. You can also run JavaScript in Web Workers to avoid blocking the main thread.
synthetic
How would you draw a page?
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.
Perhaps a naive approach to this problem is to raster parts within the viewport. If the user scrolls the page, the raster frame is moved and the missing sections are filled in with more rasters. This is how Chrome handled rasterization in its first release. Modern browsers, however, run a more complex process called compositing.
What is composition?
Composition is a technique for dividing parts of a page into multiple layers, rasterizing them individually, and combining them into a single page in a separate thread called a synthesizer thread. If scrolling happens, because the layer has been rasterized, all it has to do is compose a new frame. Animation can be done in the same way by moving layers and compositing new frames.
You can use the Layers Panel in DevTools to see how your site is divided into Layers.
layered
To figure out which elements need to be in which layers, the main thread traverses the layout tree to create a layer tree (this part is called “update layer tree” in the DevTools performance panel). If parts of the page that should be separate layers (such as slide-in side menus) are not available, you can prompt the browser by using the will-change attribute in your CSS.
The CSS attribute will-change provides web developers with a way to tell browsers that an element is about to change, so that browsers can optimize it before it actually changes. This optimization prepares some of the more complex calculations ahead of time, making the page more responsive and responsive.
You might want to provide layers for each element, but composing over too many layers can result in slower operations than a small portion of a rasterized page per frame, so measuring the rendering performance of your application is critical. See Stick to Compositor-only Properties and Manage Layer Count for more details.
Main thread grating and composition
Once the layer tree is created and the drawing order determined, the main thread submits this information to the synthesizer thread. Composite threads and then raster each layer. A layer can be as large as the entire length of the page, so the synthesizer thread divides them into blocks and sends each block to the raster thread. Raster threads raster each tile and store them in GPU memory.
The synthesizer thread can prioritize different raster threads so that things in (or near) the viewport can be rasterized first. A layer also has multiple tiling of different resolutions to handle things like zoom operations.
After the slice is rasterized, the synthesizer thread collects the slice information called drawing quadrilateral to create the synthesizer frame.
Draw a quadrilateral | Contains information such as the location of the tiles in memory and the location of the tiles to draw on the page with page composition in mind. |
---|---|
Synthesizer frame | A collection of drawing quadrangles that represent a page frame. |
Submit the synthesizer framework to the browser process via IPC. At this point, another synthesizer framework can be added from the UI thread used for browser UI changes, or from another renderer process used for extensions. These synthesizer frames are sent to the GPU to display them on the screen. If a scrolling event occurs, the synthesizer thread creates another synthesizer frame to send to the GPU.
The advantage of composition is that it is done without involving the main thread. The synthesizer thread does not need to wait for style calculations or JavaScript execution. This is why compositing animation only is considered the best choice for smooth performance. If you need to recalculate the layout or draw, the main thread must be involved.
conclusion
In this article, we examine the rendering pipeline from parsing to composition. I hope you read more about optimizing web site performance.
In the next and final article in this series, we’ll look at synthesizer threads in more detail to see what happens when user input such as mouse movements and clicks comes in.
Some of the links involved in the article need to turn over the wall, if there is a need to translate, you can leave a message to me ~