Believe you front-end students, have encountered such an interview question: from the browser input URL, to the page display process, what happened?
There have been quite a few writers on the Nuggets who have published a complete answer to this question. From URL parsing, DNS parsing, and then to the browser to generate Render Tree and Render page, covering the network layer and application layer of all aspects of knowledge, belongs to a more open topic. This article will look beyond the web protocol layer and talk about Chrome’s work in this process.
Chrome’s multi-process architecture
When you’re using Chrome, open up the system processes list and you’ll find a number of Google Chrome processes already running.
You may be wondering: Why do I have so many processes when I only have one Chrome app open?
Unlike typical single-process applications, Chrome is built around a multi-process architecture, with each Process doing its job and communicating with each other through Inter Process Communication.
Introduction to each process
- Browser: Controls the “Chrome” part of the application, including the address bar, bookmarks, back and forward buttons. It also handles the invisible privileged parts of the Web browser, such as network requests and file access.
- Renderer: Controls the display of any content within a TAB. Each TAB and its iframe are assigned a Renderer process.
- Plugin: Controls the use of any plug-ins for your site, such as Flash.
- GPU: Processes GPU tasks independent of other processes. It is split into a separate process because the GPU processes requests from multiple applications and draws them on the same interface.
- -Penny: Extension.
- Utility: tool process.
Benefits of a multi-process architecture
Chrome takes advantage of the multi-process architecture to ensure job stability. Suppose you have three tabs open, each run by a separate renderer process. If one of the tabs crashes, you can close that TAB while keeping the other tabs running. But if all tabs are running on one render process, then one TAB crash will crash with all of them.
But more processes mean more memory, and to save memory, Chrome limits the number of processes it can start. This limit depends on the memory and CPU capacity of the device, and when Chrome reaches the limit, it merges Renderer Processes running on multiple tabs on the same website into one.
Chrome applies the same approach to the Browser Process, running each part of it as a service that can be easily split into different processes or aggregated into a single Process.
Navigation phase
Step 1: Process the input
When a user enters content in the Browser address bar, the UI Thread of the Browser Process is responsible for processing the user’s input and deciding whether to direct the user’s input to the search engine or treat it as a website address.
Step 2: Establish a network connection
The UI thread notifies the network thread and sends network requests to the other site. The network thread determines the host address through the appropriate protocol, DNS lookup, establishes TCP connections, and establishes HTTPS connections through TLS negotiation.
Step 3: Receive the response
Upon receiving a response from the other site, the network line checks the status code and notifies the renderer process that the error page will be rendered if an error code begins with a 4 or 5.
If it is a redirected status code, a new URL is requested.
If it is a successful status code, the content-Type response header is judged. If it is an HTML format, the HTML security check is performed to ensure that it is not a dangerous site and the Cross Origin Read Blocking (CORB) check is performed to exclude sensitive cross-site data. If it’s in another format, such as PDF, ZIP, etc., parse it as much as possible and display it, play it in your browser, or download it locally.
Step 4: Assign/create a render process
When the web thread is ready to do its job, the UI thread is notified, and the UI thread assigns a renderer process to the site. In step 2, when the UI thread tells the network thread to set up the network connection, it starts creating the renderer process early because it is not clear how long the network thread expects to complete its work. When the network thread is done, the renderer process is immediately available. One exception is when the request is redirected, and the pre-created renderer process is wasted, it is wiped out and a new process is created.
Step 5: Complete the navigation
Now that the data and renderer processes are ready, the browser process sends IPC to the renderer process to submit navigation, along with HTML data. Once the browser process receives confirmation from the renderer process, the navigation is complete, a new record is inserted into the browser history, and the navigation bar is updated with the new site address.
If a Service Worker is introduced
A Service worker is an event-driven worker registered with a specified source and path. It uses JavaScript to control associated pages or websites, intercepts and modifies access and resource requests, and cache resources in a fine-grained manner. You have complete control over how your application behaves in certain situations, most commonly when the network is unavailable.
When navigation occurs, the network thread checks in the Service Worker scope to see if the currently requested URL is registered with the Service Worker, and if so, the UI thread looks up the renderer process to execute the Service Worker code. The Service Worker might read the page from the local cache without having to send a network request.
Rendering phase
This stage of the work is mostly done by the renderer process, whose core job is to transform HTML, CSS, and JavaScript into a web page that users can interact with.
The renderer process includes the following threads:
- The main thread handles most of the code.
- Worker is used to share the main thread computation, but does not have access to the DOM.
- Synthesizer threads and raster threads are used to render pages efficiently and smoothly.
Step 1: Parse the document
The main thread of the renderer process parses the HTML document top-down, generating a tree structure called the DOM. The parsing method is determined by the HTML specification, and the HTML specification also provides more elegant fault tolerance schemes to ensure error tolerance during parsing:An introduction to error handling and strange cases in the parser .
External non-blocking resources, such as images and CSS files, are requested by the main thread while parsing the build DOM. But
Preload the scanner
To speed up document parsing, the “preload scanner” scans the required high-priority resources, such as CSS, JavaScript, and Web fonts, as soon as the main thread starts parsing the document and reports them to the network thread, which starts downloading them. With any luck, by the time the main thread resolves to the current node, the corresponding resource may have already been downloaded.
<link rel="stylesheet" src="styles.css"/>
<script src="myscript.js" async></script>
<img src="myimage.jpg" alt="image description"/>
<script src="anotherscript.js" async></script>
Copy the code
How script is loaded
When parsing reaches the
async
This command is executed immediately after the script is downloadeddefer
The command is executed immediately after the script is downloaded and the document is parsedDOMContentLoaded
The event- But neither can parse the document while executing the script
rel=”preload”
By setting rel=”preload” to the tag, resources can be loaded and made available sooner and it is less likely to block the initial rendering of the page, thus improving performance. Use the AS attribute to declare its resource type, such as script, style, audio, image, and so on. MDN’s explanation for this: developer.mozilla.org/zh-CN/docs/…
Step 2: Calculate the style
The main thread parses the CSS, decides which Style to apply to which node based on the CSS selector, calculates the Style of each DOM node, and merges it with the browser’s default CSS Style to generate Style Rules.
Step 3: Layout
The goal of this step is to calculate the geometry of the node based on DOM structure and Style Rules.
The main thread traverses the DOM Tree and Style Rules to generate a Layout Tree that contains the x and Y coordinates of the node and the size of the box.
A Layout Tree is structured like a DOM Tree, but it only includes the nodes visible on the page. For example, a Layout Tree does not include nodes that display: None, but that visibility: hidden, both of which are included in the DOM Tree. Are there any nodes that the Layout Tree contains that the DOM Tree doesn’t? Yes, there are pseudo-elements like ::after, ::before.
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 placed. 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.
Step 4: Draw
In the drawing phase, the browser has the DOM, Style Rules, and Layout Tree, which determines the size, shape, and position of the nodes. Now it needs to determine the Paint Records (i.e. the order in which to draw them) based on these data.
If you draw directly in HTML tag order, the arrangement of some elements with the Z-index attribute is probably wrong.
The cost of updating the rendering pipeline is high
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, the script modifs the DOM structure, adds a new node, and the rendering pipeline is started to regenerate the affected parts of the Layout Tree and Paint Records.
Break the script into small pieces for execution
Most of our monitors refresh the screen 60 times per second (60 FPS), and browsers generally match that, since it doesn’t really make sense to go beyond that. The time between refreshes is called a frame, and if you animate the element and make sure it moves between frames, the animation will look very smooth visually.
However, if a long script is executed during this process and blocks the main thread (both page rendering and script execution are performed by the main thread), the animation on the timeline will lose frames and look visually sluggish.
To keep the page running smoothly, it is recommended to break the JavaScript script into small pieces and use requestAnimationFrame() to run the script between each frame.
For a script with a lot of computation, try to execute it in the Web Worker to avoid preempting the main thread resources.
Step 5: Synthesize
The browser obtains the structure of the document, the style, geometry and order of each element, and finally converts this information into pixels on the screen, a process called Rasterizing.
The first version of Chrome rasterized the current viewport, the visible part of it. As the page scrolls, move the raster frame, rasterizing more content to fill in the missing parts of the viewport. As you can imagine, this makes for a poor user experience when scrolling.
Chrome later implemented a more complex and better experience of rasterization calledsynthetic(compositing). 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 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 see how the page is layered in the Layers panel of F12.
There are specific properties and elements that can instantiate a layer, including
The specific steps of synthesis
- To figure out which elements need to be in which layers, the main thread traverses the Layout Tree to create/update the Layer Tree, feeding that information to the synthesizer thread
- The synthesizer thread will divide a large layer into smaller blocks and hand them to the raster thread
- The raster thread rasterizes the small graph blocks, and the rasterized information is called Draw quads, which is stored in GPU memory
- The synthesizer thread collects and draws the quadrilateral and creates a composite frame
- The synthesized frame is sent via IPC to the browser process, which in turn sends it to the GPU for display on the screen
The whole synthesis process is quite complicated, what is the purpose of such a complicated process?
Benefits of synthesis
The first is the fragmentation of large layers by multiple raster threads in parallel, which is particularly useful when only part of the page is being rerendered, because the renderer process can raster only the blocks that need to be rerendered, while the remaining blocks are drawn from GPU memory.
Second, the composition process is independent of the main thread. As mentioned above, the rendering pipeline runs on the main thread and is expensive to update. Keeping the compositing process separate will help the browser get smoother performance. At present, some CSS properties, such as transform and opacity, can be accelerated by GPU when elements are modified by animation, without going through the rendering line and directly entering the synthesis step.
conclusion
Data flow between Chrome threads:
This article explains what Chrome does in page rendering. There’s a lot of reference to official documentation, and I’ve simplified a few steps in order to make the process simple and clear. If you don’t understand something, please leave a message and tell me, or go to the original document.
Refer to the link
Inside look at modern web browser
Render pages: How browsers work
High Performance Animations