First, look at a simple piece of code
const sNode = document.getElementById('span'); let i = 0; while(1){ if(i>10000000000){ break; } i++; }}) snode. innerText =' 32' return (<div> <span ID ='span'> hello </span> </div>)Copy the code
Its effect is shown below
2. From this we get a general shape
Because the browser seems to be waiting for our JS code to finish rendering.
Three, introduce the composition of modern browser
- Browser process: Controls chrom’s user interface outside of tabs, including the address bar, bookmarks, back and forward buttons, and coordinates with other processes in the browser
- Network process: responsible for initiating and receiving network requests
- GPU process: responsible for rendering the entire browser interface
- Plugin process: Responsible for controlling the plugins that are still used on the site. I’m not talking about extensions installed in development mode on the Chrom market. I’m talking about plug-ins like Flash
- Renderer process: Used to control and display the contents of a TAB. By default, browsers create a process for each TAB
The reason why I say default here is because it has to do with the process model you choose when running Chrom! The default Process model is process-pre-site-instance, and there are other advantages of the process-pre-site-instance Process model: it is safe, fast, and smooth. The downside is also obvious: every time a new SiteInstance is opened, it takes up memory. In this mode: Chrome creates a renderer process for each Siteinstance (linked from one page to the same Siteinstance), but this process is limited! It’s based on your machine, your machine has a lot of memory, so you have a lot of renderer processes, if I can only create 20 siteinstances, what happens when I open a TAB and type in a url, and the renderer process, You will randomly select one of the first 20 processes to execute the SiteInstance you are now creating
Three, the work process
Instead of entering the url in the address bar and retrieving the data, we go directly to the background and return the data to the browser process
- This is when the Browser process passes data to the Browser process (our page) via the IPC process communication pipeline.
——- now officially enter the rendering process. ——- Render process and core task is to render HTML, CSS, JS, image and other resources into web pages that users can interact with
-
The main thread of the Browser process parses the HTML to construct Dom data structures.
-
Tokeniser is the first tokeniser to parse input HTML content into multiple tags through lexical analysis. DOM tree construction is carried out
-
During DOM Tree construction, the Document object is created, and the DOM Tree with the Document as its root node is constantly modified to add elements to it.
-
HTML code often introduces some additional resources, such as images, CSS, JS scripts, etc. Images and CSS resources are downloaded over the network or loaded directly from the cache. These resources do not block HTML parsing, so they do not affect DOM generation. When a script tag is encountered.
-
In the process of parsing HTML files, if you encounter script tags, you will stop the HTML parsing process, and instead load parsing and execute Java Script. Why can’t you skip the HTML parsing process like CSS and images, and stop at js? Wait and execute JS before proceeding to HTML parsing
-
This is because the browser does not know if the script executed by JS will change to the DOM Tree that is currently being constructed. For example, if the document.write method is called in the JAVASCRIPT code to modify the HTML, the previous HTML parsing will be meaningless. That’s why we put the script tag under the body. Because in the process of parsing HTML, encountered JS will stop! The HTML will be parsed after running JS, and the result will be a blank screen! Of course placing the script under the body is one way, and you can also defer and async to load the script
-
When the HTML is parsed, we get a DOM Tree, but at this point we don’t know what each DOM Tree node should look like.
-
At this point, the main Thread of the Browser Process needs to parse the downloaded CSS and determine the calculation style for each DOM node. (Even if you do not provide a custom CSS style, the Browser will have its own default style sheet. The source code is available in Chrome.)
-
This is the DOM Tree at this point
-
Next we need to know where each node fits on the page (i.e. its coordinates and how much space it occupies) ——– This stage is called Layout
-
The main Thread of the Render Process generates the Layout Tree by iterating through the DOM and calculating the style
-
Layout Tree X, Y coordinates and border sizes are recorded on each node. Note that DOM Tree and Layout Tree are not one-to-one! For example, if a DOM Tree has a display: None attribute, the DOM Tree node exists but the Layout Tree node does not.
Similarly, if you add a Content property value to the before pseudo-class, it will be displayed in the Layout Tree, not the DOM Tree. This is because DOM is obtained through HTML parsing and doesn’t care about style. The Layout Tree is generated from the DOM Tree and the calculated style
DOM Tree: It is obtained from HTML parsing
Layout Tree: It is generated from the DOM Tree and the calculated style. It corresponds to the node shown on the screen at the end.
- At this point we know the size, shape, and position of the element. This is not enough, we must also know in what order to draw the Paint node. We know that z-index can change the hierarchy, so be sure to draw the Paint nodes in order, or you’ll end up with the joke of putting a dog’s head in front of a person
- So to make sure that the correct hierarchy is displayed on the screen, the main Thread traverses the Layout Tree and creates a Paint Record that describes the order in which the layers are painted. ————- This stage is called paint and the main thread traverses the Layout Tree to generate the Layer Tree (the first layout Tree traverses generates the Paint Record and the second layout Tree generates the Layer) The tree)
Here we can summarize how the main thread of the renderer process works:
-
Now that you’ve determined the document’s drawing order and Layer Tree, it’s time to finally convert this information into pixels for display on the screen. This behavior is called Rastering.
-
Early Rastering only rasters the user’s Viewport, but as the user scrolls the page, rasterize more content to fill in the missing parts. The problem with this approach is obvious! This can cause a delay in presentation.
-
Now, Chrome uses a more complex rastering process called composting. Composting is a technique for dividing parts of a page into multiple layers, rasterizing them separately, and compositing them separately in composting threads. It is simple: It’s better if the elements are layered and rastered. It’s better if the elements are rastered. Then you just need to combine the contents of the viewport into one frame. Just show it to the user
> The specific process of simplification is as follows!
- The main Thread of the Render Process parses the HTML and generates the DOM Tree
2. Generate a Layout Tree by traversing the DOM Tree and calculating the style
- Paint the record table by traversing the Layout Tree
- The main Thread then posts the Paint Record and Layout Tree to the composting Thread.
- The composting Thread divides layers according to rules and passes each layer into smaller tiles to the raster Thread for rasterization.
- After rastering is finished, the composting Thread will receive drow quads from the rastering Thread
- Based on these drow quads, the composting thread composts a composting frame.
- The renderer Process then passes composting frames to the Browser Process via IPC.
- The browser process passes the synthesizer frame to the GPU process for rendering, and it’s displayed on your screen.
- Similarly, when we slide down the screen, the synthesizer thread regenerates the synthesizer Frame, which is then returned to the browser process and rendered to our page by the GPU process
Backflow and redraw
Backflow: When we change the geometry of an element, we re-evaluate the style, layout, paint, etc
Redraw: When we change the color and appearance of an element without affecting the properties of the layout, the style calculation is redone, but the layout calculation and drawing are not performed
From the above analysis, we found that redraw and rearrangement occupy the main thread of our renderer process. The result is that the screen drops frames
> < p style = “margin-bottom: 0pt; margin-bottom: 0pt; What else occupies the main thread
The answer is that javascript is going to occupy the main thread of our renderer process. Since they’re all on the main thread. This leads to a problem: preempting execution time! If you write an animation that constantly rearranges and redraws, the browser needs to run style, layout, and draw operations on every frame. We know that when a page is refreshed at 60 frames per second, it doesn’t get stuck. If you run an animation, you also need to perform a lot of jS tasks. When there is time left after the style calculation, layout, and drawing are completed within a frame, js will preempt the main thread and acquire the use of it. If the JS task is too long! The main thread is not returned in time for style calculation, layout, and drawing at the beginning of the next frame. This results in the next frame of the animation not being rendered, which results in a lag effect
> < p style = “max-width: 100%; clear: both; min-height: 1em;
You can use the requestIdleCallback API. He can split up the JS task and execute it after every frame so it doesn’t affect the rendering
Let’s see what happens to the code execution after this process. Is it as good as we imagined?
Its effects do not affect rendering, but prolong JS execution time!