Once we get the resources from the server, how do we render the browser, and how do we render the page

One browser Render

Basic understanding of browser rendering

See starting from 0 for a thorough understanding of browser rendering

From left to right, we can see the browser rendering process as follows:

1. Parse HTML, generate DOM tree, parse CSS, generate CSSOM tree (CSS Object Model,CSS Object Model, there are many apis, including style rules- internal style sheet all CSS rules) 2. Combined DOM Tree and CSSOM Tree to generate the Render Tree. 3.Layout: based on the generated rendering Tree, perform backflow to obtain the geometric information (location, size) of nodes. 5. Display: Send the pixel to the GPU and display it on the page. (There is more to this step, such as merging multiple compositing layers into one layer on the GPU and displaying them on a page. The principle of CSS3 hardware acceleration is to create a composition layer.)Copy the code

So what is the process of combining DOM Tree and CSSOM Tree to generate Render Tree?What does the browser do when it combines the DOM Tree with the CSSOM Tree to generate the Render Tree

1. Traverse each visible node starting from the root node of the DOM tree. 2. For each visible node, find the corresponding rules in the CSSOM tree and apply them. 3. Generate a render tree by combining each visible node and its corresponding style.Copy the code

Now that we’re talking about traversing the visible nodes, we need to know what nodes are not visible. Invisible nodes include:

1. Nodes that do not render output, such as script, meta, link, etc. 2. Some nodes are hidden using the CSS. Such as display: none. Note that nodes hidden with opacity and opacity will still be displayed in the rendering tree. Only nodes with display: None are not displayed in the rendering tree.Copy the code

Will I never be able to introduce a render to the page? Then we should learn about threads in the browser

2 Browser threads

Threads (English: thread)

Is the smallest unit in which an operating system can schedule operations. It is contained within the process and is the actual operating unit within the process. A thread is a single sequential flow of control in a process, and multiple threads can be concurrent in a process, each performing a different task in parallel

To learn more, see this article on multi-process and JS threads in browsers

Key knowledge:

A process has one or more threads that work together to complete tasks assigned by the process. 2. Every time the browser opens a TAB, it creates a separate browser processCopy the code

My understanding:

To open a web page is to open a process, but there may be page rendering, scrolling, etc. These are all by different threads to complete the task assigned by the whole process

Browsers are multi-threaded, divided into: GUI rendering thread, JS engine thread, event trigger thread, timing trigger thread, asynchronous HTTP request thread

Each thread is responsible for:

1. GUI rendering thread
This thread is responsible for rendering the browser interface, including parsing HTML, CSS, building DOM trees, Render trees, layout and drawing, etc. This thread executes when the interface needs to be repainted or reflow due to some operationCopy the code
2.JS engine threads
The JS kernel, also known as the JS engine, is responsible for processing the arrival of tasks that execute javascript scripts, wait for the task queue, and then process them. The browser has only one JS engine running JS programs at any timeCopy the code
3. The event triggers the thread
It sounds like JS execution, but it belongs to the browser, not the JS engine, and is used to control the time loop (understandably, the JS engine is too busy on its own, Browser need to start another thread to help) when JS engine execution code blocks such as setTimeout (can also be other threads from the browser kernel, such as mouse clicks, AJAX asynchronous requests, etc.), will correspond to the tasks added to the event thread when the corresponding event in line with the trigger condition is triggered, the thread will add events to the pending queue of a party, Note: Due to the single-threaded nature of JS, the events in the queue must be queued to be processed by the JS engine (when the JS engine is idle).Copy the code
4. The timing trigger thread
SetInterval and setTimeout thread timing timer is not timed by the JS engine, because if the JS engine is single-threaded, if the JS engine is blocked, it will affect the timing accuracy. When timing completion is triggered, the event will be added to the event queue, waiting for the JS engine to idle to execute. Note: According to the HTML standard of W3C, the interval between setTimeout and 4ms is 4msCopy the code
5. Asynchronous HTTP request threads
If a thread that XMLHttpRequest starts after the connection detects a change in the state of the request, the thread will add the callback function to the event queue, if any, until the JS engine is free to executeCopy the code

So which threads are responsible for loading and rendering HTML files?

3. How browsers work

Reference: How browsers work

When the browser gets an HTML file, it loads it ‘from the top down’ and parses and renders it during the load. CSS is introduced to execute the load, and the program is still executed down, but the thread is interrupted until the

Into the web resources that can get the corresponding code, the browser will open up a stack memory in memory, is used to provide code execution environment, assigning a thread to execute code rows at the same time, to parse HTML, CSS, DOM tree, Render tree construction, layout and drawing is the distribution of GUI rendering thread, such as when we meet with Lin K tag, SRC inside link, right? At this time, the browser for the introduction of external resources, is no longer using GUI rendering thread, but using HTTP asynchronous request thread, encounter image resources, the browser will also issue another request (also in the HTTP asynchronous request thread request image), to obtain the image resources. This is an asynchronous request and does not affect the loading of the HTML document. So when the external CSS comes back, it goes to the Task Queue to see if anything needs to be rendered in the task Queue after everything in the main thread of the GUI rendering thread has been rendered, so that’s why only the DOM tree and things other than meta, link, img are rendered for the first time. However, what about the srCIPT tag? The HTML document suspends the render (load parsing render synchronization) thread, not only waiting for the JS file in the document to complete loading (js engine thread), but also waiting for parsing to complete before resuming the RENDER thread of the HTML document. Since JS is single-threaded, but browsers are multi-threaded, the loading of script, meta, link, etc tags is not something that the rendering thread does

Why does a script interrupt a program and continue execution when it encounters link?
Reason: Link is an asynchronous resource request, which does not affect the synchronous code. JS may modify the DOM, the most classic document.write, which means that before the completion of JS execution, the download of all subsequent resources may be unnecessary, which is the root cause of JS blocking subsequent resource download. Solution: You can place externally referenced JS files before </body>.Copy the code

Now understand the most important thing, reflux and redraw

Two return

1. Basic concepts of reflux

By constructing the render tree, we combine the visible DOM nodes with their corresponding styles, but we also need to calculate their exact position and size in the device viewport. This stage of calculation is called backflow

2. When does backflow occur

The backflow phase computs the location and geometry of nodes (size, position, etc.), which is required when the page layout and geometry information changes

Specific include:

1. Add or remove visible DOM elements. 2. The size of the element changes (margin, inner border, border size, height, width, etc.) 4. Content changes, such as text changes or an image being replaced by another image of a different size. 6. The browser window size changes (because backflow calculates the location and size of elements based on the viewport size)Copy the code

According to the scope and degree of change, big or small part of the render tree needs to be calculated, some changes will trigger the rearrangement of the whole page, for instance, a scroll bar appears or modify the root node, reflux is sure to lead to redraw, every redraw caused additional computing consumption, impact performance, can lead to a page appears time-consuming, Browsers slow down, so avoid backflow and redraw as much as possible

So what is redrawing?

Three redraw

1. Redraw basic concepts

By constructing the render tree and the backflow phase, we know which nodes are visible, as well as the style of the visible nodes and specific geometric information (location, size). Then we can convert each node of the render tree to the actual pixels on the screen. This phase is called the redraw node.

It shows that backflow must cause redrawing, and redrawing is not necessarily due to backflow. So what are the redrawing that is not caused by backflow, mainly by changes in style, and the following changes will cause redrawing

visibility, color,background-color
Copy the code

Repainting will affect performance, so we should avoid repainting as much as possible. How to reduce backflow and repainting

How to avoid reflux and redrawing

How to avoid backflow and redraw is also an important knowledge of performance optimization

1. Use the MVVM framework

React and Vue, the virtual DOM, and diff algorithms have been better encapsulated and optimized for reflux and redraw

2. Read/write separation

The browser forces a queue refresh when you retrieve layout information from an operation, such as when you access the following properties or use the following methods:

ScrollTop, scrollLeft, scrollWidth, scrollHeight ClientTop, clientLeft, clientWidth, clientHeight getComputedStyleLI getBoundingClientRectCopy the code

So what’s the effect of refreshing the queue? Let’s look at a couple of examples

  <div id="test">Test reflux and redraw</div>
Copy the code
 let test = document.getElementById('test')
 test.style.width = '200px'
 test.style.height = '100px'
 test.style.marginLeft = '10px'
 console.log(test.clientWidth)
Copy the code

How many times do you think backflow occurred in the code above?

The first line does not perform the test operation, so it must not trigger backflow. The second line changes the width. In fact, no, it’s only once. The old browsers used to have maybe three times, but today’s browsers have batch rendering mechanisms, such as putting your DOM margin changes in a queue, and only drawing once after all the queue operations are done. The above 3 changes only cause a backflow. When you finish the second line, the browser will wait to automatically check if the next line is also changing the style. All three lines are finished, put in a queue, and I will render all the same

So let’s do the next example

  <div id="test">Test reflux and redraw</div>
Copy the code
 let test = document.getElementById('test')
 test.style.width = '200px, '  / / the second line
 console.log(test.clientWidth)
 test.style.height = '100px' / / in the fourth row
 test.style.marginLeft = '10px'; / / the fifth row
Copy the code

How many backflows do you feel up there? If I get to the second line, I put test.style.width = ‘200px’ in the queue, but I get the layout information in the next line, which forces the queue to refresh, and there is a backflow, so the bottom line is put in the new queue, which causes a backflow

As you can see from the above, separate reads and writes reduce redrawing

3. Style set changes

So let’s say I could rewrite the top

  <div id="test">Test reflux and redraw</div>
Copy the code
 .test {
    width: 200px;
    height: 100px;
    margin-left: '10px';
 }
Copy the code

Let the style focus render, become a backflow, reduce the number of renders

4. Cache processing, in fact, is separate read and write

  <div id="test">Test reflux and redraw</div>
Copy the code
 test.style.width = test.clientWidth + 10 + 'px'
 test.style.height = test.clientHeight + 10 + 'px'
Copy the code

I redraw the top twice, and I redraw the bottom once

const tClientWidth = test.clientWidth
const tClientHeight = test.clientWidth
test.style.width = tClientWidth  + 10 + 'px'
test.style.height = tClientHeight + 10 + 'px'
Copy the code

5. Batch modify elements

 <div id="test">Test reflux and redraw</div>
Copy the code
for (let i = 0; i < 5; i ++ ) {
  let newLi = document.createElement('li')
  newLi.innerHTML = i
  test.appendChild(newLi)
}
Copy the code

There were five backflows

How do we turn it into a reflux? That is, make batch changes

5.1 use createDocumentFragment

The CreateDocumentFragment () method creates a virtual node object that contains all the properties and methods. The createDocumentFragment() method is used when you want to extract a part of a document, change, add, or delete something and insert it at the end of the document. You can also use the document object of the document to perform these changes, but to prevent the structure of the document from being destroyed, the createDocumentFragment() method makes it safer to change the structure and nodes of the document.

The createdocumentfragment() method creates a DocumentFragment node. If multiple dom elements need to be added to the DocumentFragment, adding these elements to the DocumentFragment first and then adding the DocumentFragment to the page will reduce the number of times the page renders the dom. Efficiency will increase significantly

You can store it in createDocumentFragment first and then put it in as a whole

    let frg = document.createDocumentFragment()
    for (let i = 0; i < 5; i ++ ) {
      let newLi = document.createElement('li')
      newLi.innerHTML = i
      frg.appendChild(newLi)
    }
    test.appendChild(frg)
    frg = null Destroy immediately after use
Copy the code
5.2 Direct String Concatenation
    let str = ' '
    for(let i = 0; i < 5; i ++) {
      str += `<li>${i}</li>`
    }
    test.innerHTML = str
Copy the code

6. Use positioning elements instead of margins

Because the positioning element has been removed from the standard flow, even if there is some redrawing of the positioning child element, it is the non-standard flow that affects the element at this level, and not the whole large standard flow

7. Use cSS3 new style

In normal times, we can use transform instead of transform to enable hardware acceleration with transform and opacity, which will not cause backflow and redrawing

As for why, please read this article I wrote. It’s very important