preface
Hello, everyone. I’m a fellow student. It’s autumn again, and many of you are starting to look back on the study plan you made at the beginning of the year. Emmmm, it’s a long story, but the most important thing is now. Today, let’s learn how to do a very simple yet invisible x job: million-level list rendering. Ok, so beep beep so much, let’s learn to learn.
The body of the
At first it was
As we all know, JS is a single-threaded language, and dom operations (such as insert, delete, etc.) bring huge performance loss, for example, we insert 100W Li to a UL, what will happen?
Try to run it?
<! 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></ul>
<script>
const targetElement = document.querySelector('ul')
for(let i=0; i<1000000; i++){const li = document.createElement('li')
li.innerHTML = Math.random()
targetElement.appendChild(li)
}
</script>
</body>
</html>
Copy the code
If you are good at computer, the fan of your laptop should have accelerated the work, and then there appears a picture like this, the problem is not big, the computer has not blue screen, indicating that the writing is ok.
Of course, as professional front-end engineers, we can also let users choose to upgrade the CPU, change a computer and so on as a solution.
And then I’ll do this
But as a front-end engineer, the other is not important, but must be SAO ah, that we have to find there is no SAO operation?
Thinking: the purpose is to insert 1 million pieces of data, as long as the user can see the data for the first time with the human point of view and feel the silk is not smooth? Start with two points:
- Reduce DOM operations: DOM operations are very performance destructive. If you can reduce dom operations on the premise of ensuring a small number of DOM operations (which can be completed in a short time), the running speed can be greatly improved.
- Time-sharing insertion: Js single thread mechanism causes that if a task takes longer in a period of time, other tasks cannot be carried out. For example, we keep inserting data, rendering cannot be done, and there will be no content update and it will be stuck. We allocate time to the operation. For example, on the premise of not affecting the user’s viewing, we divide the task into multiple times to do. Simply speaking, we insert part of the task first, and then render part of the task.
And then I do this again
After some moving, I came to the following conclusion:
createDocumentFragment:
Take a look at the official document:
Understand:
- To create a
dom
Node, and not in the masterdom
Tree, simply understood as “virtualdom
“; And insert intodom
In the tree, only the descendants of the virtual node will appear, which is trueThings brushed clothes go, deep and name - This node exists in memory, so any operation on this node will not cause the page to flow back;
requestAnimationFrame:
Understand:
- A function is executed before each frame is redrawn, perfect for animation.
If you are careful, you must ask: why not use setTimeout and setInterval?
There are two main advantages:
requestAnimationFrame
It’s going to take all of the framesDOM
The operations are centralized and done in a single redraw or reflow, and the redraw or reflow interval closely tracks the browser refresh rate, which is typically 60 frames per second.- In hidden or invisible elements,
requestAnimationFrame
There will be no repainting or reflow, which of course means lesscpu
.gpu
And memory usage.
I’ll do it at the end
Go straight to the code. It’s all in the comments
<! 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></ul>
<script>
// createDocumentFragment
// requestAnimationFrame
// Millions of pieces of data
let total = 1000000;
// Single insertion can be customized
let once = 20;
// The number of inserts to be rounded up
let loopCount = Math.ceil(total / once);
// Current render count
let countRender = 0;
function render() {
// The target object to insert
const targetElement = document.querySelector("ul");
// Because the document is in a fragment in memory and not in the DOM tree, inserting all child elements into the document fragment does not cause page backflow (calculation of element position and geometry). Therefore, using document fragments generally results in better performance.
// Creating a virtual Dom node does not trigger Dom rendering, backflow, etc., before inserting it into the real document
// Therefore, the performance cost of DOM manipulation can be greatly reduced
const fragment = document.createDocumentFragment();
// Inserting a DOM node into a virtual node does not trigger a real DOM operation, as above
for (let i = 0; i < 20; i++) {
// Create a node
const li = document.createElement("li");
// Do something for Li
li.innerHTML = Math.random();
// Insert into the virtual node
fragment.appendChild(li);
}
// When inserting a real node, only descendant nodes under the virtual fragment are inserted
targetElement.appendChild(fragment);
// The number of renders is increased by 1 to control the number of recursions
countRender++;
// // recursive call
if (countRender < loopCount) {
/ / window. RequestAnimationFrame () telling the browser - you want to perform an animation, and require the browser until the next redraw calls the specified callback function to update the animation.
// The number of callbacks is usually 60 per second, but in most browsers that follow W3C recommendations, the number of callbacks usually matches the number of browser screen refreshes.
// The ability to summarize each DOM operation and update the animation frame before the next redraw
// Therefore, under the browser's single-threaded mechanism, it is possible to load million-level lists without stalling
window.requestAnimationFrame(render); }}// Perform rendering
render();
</script>
</body>
</html>
Copy the code