How browsers render
Browser workflow: Build DOM -> Build CSSOM -> Build render tree -> Layout -> Draw.
- First, parse the received document and build a DOM tree according to the document definition. DOM tree is composed of DOM elements and attribute nodes
- Then the CSS is parsed to generate the CSSOM rule tree
- The node of the rendering tree is called the rendering object, which is a rectangle containing properties such as color and size. The rendering object corresponds to the DOM element first, but the corresponding relationship is not one-to-one. Invisible DOM elements will not be inserted into the rendering tree. There are also DOM elements that correspond to several visible objects, which are typically elements with complex structures that cannot be described by a rectangle
- When render objects are created and added to the tree, they have no location or size, so when the browser generates the render tree, it will be laid out according to the tree (also known as backflow). At this stage, all the browser has to do is figure out the exact position and size of each node in the page, and this behavior is usually “automatically rearranged” by Chen Wei.
- The layout phase is followed by the Paint phase, which iterates through the render tree and calls the paint method of the render objects to display their contents on the screen, drawing using the UI base components
It is important to note that this process is complete, in order to better user experience, rendering engine will as early as possible will be displayed on the screen, do not wait for after all HTML parsing to build and render tree layout, it is part of parsing the display part of can also download other content through the network at the same time
For detailed information, please refer to: “Browser rendering Principle”, “Browser rendering Principle Introduction”, “Front-end Required reading: Internal working Principle of browser”, “Simple Browser rendering Principle”.
Why is DOM manipulation slow
Because DOM belongs to the rendering engine, and JS belongs to the JS engine, when we operate DOM through JS, in fact, this operation involves communication between two threads, so it is bound to bring some performance loss. Manipulating the DOM more than once means that threads are communicating with each other, and manipulating the DOM can cause redraw backflow, which can lead to performance issues.
Insert tens of thousands of DOM, how to achieve page free lag?
First of all, we might not be able to insert tens of thousands of DOM’s all at once, which would definitely cause a lag, so the key to solving the problem is how to render the DOM in batches.
-
The way most people think about it is through a requestAnimationFrame loop
** When rendering large data, use createDocumentFragment and requestAnimationFrame properly to split operations into small segments.
**documentFragment: ** is a virtual Dom list that stores XML fragments (EL elements) to be processed. Since it is not in the real Dom structure, operations on it do not trigger backflow in the browser, but only once when the Dom is inserted.
Multiple dynamically generated divs were inserted into the virtual node, and only one insertion was made after the final completion, triggering only one backflow.
However, if the number of inserts is too high, the browser will not render properly and will lose the response. In this case, you need to increase the time interval by using setTimeout or an API-requestAnimationFrame
RequestAnimationFrame:
Features:
- RequestAnimationFrame brings together all DOM operations in each frame in a single redraw or reflow, and the redraw or reflow interval closely tracks the browser refresh rate
- RequestAnimationFrame will not be redrawn or reflow in hidden or invisible elements, which of course means less CPU, GPU, and memory usage
- RequestAnimationFrame is a browser-specific API for animation that optimizes method calls at runtime and pauses animation automatically if the page is not active, saving CPU overhead
Use:
RequestAnimationFrame is used in much the same way as setTimeout, except that the interval is not required. RequestAnimationFrame takes as an argument a callback function that is invoked before the browser redraws. It returns an integer indicating the timer number, which can be passed to cancelAnimationFrame to cancel execution of the function
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
<title>Document</title>
</head>
<body>
<ul>Render data</ul>
</body>
<script>
setTimeout(() = > {
// Insert 100,000 pieces of data
const total = 100000;
// Insert 20 at a time, reduce if you feel performance is not good
const once = 20;
// Count the number of times to render data
const loopCount = total / once;
let countOfRender = 0;
let ul = document.querySelector("ul");
function add() {
// Use createDocumentFragment to optimize new energy, insertion does not cause backflow
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const li = document.createElement("li");
li.innerText = Math.floor(Math.random() * total);
fragment.appendChild(li);
}
ul.appendChild(fragment);
countOfRender += 1;
loop();
}
function loop() {
if (countOfRender < loopCount) {
window.requestAnimationFrame(add);
}
}
loop();
}, 0);
</script>
</html>
Copy the code
-
Virtualized Scroller
The idea behind this technique is to render the content in the visible area, not the content in the non-visible area at all, and then replace the rendered content in real time while the user is scrolling.
As you can see from the figure above, even though the list is long, only a few DOM elements are rendered, and the DOM is updated in real time as we scroll through the page
React-virtualized is just a mode of production for that