subject
Concretization
There is an empty unordered list node ul on the page, whose id is list with big data. Now it is necessary to insert 10w li into the list. The text content of each list item can be defined by itself, and it is required to display the text content in the list item through alert when each li is clicked.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Page loading massive data</title> </head> <body> <ul id="list-with-big-data">100000 data</ul> <script> // Add your code logic here </script> </body> </html>
analysis
The first possible solution to this problem is to bind the elements li and ul in the listener, and then think of the possible solution to this problem in the listener.
(function() { const ulContainer = document.getElementById("list-with-big-data"); // Defensive Programming if (!ulContainer) { return; } for (let i = 0; i < 100000; i++) { const liItem = document.createElement("li"); liItem.innerText = i + 1; // The this of the EventListener callback function points to the current node by default. Be careful if you use the arrow function liItem.addEventListener("click", function() { alert(this.innerText); }); ulContainer.appendChild(liItem); } })(); Copy code
After practicing the above code, we find that the interface experience is very unfriendly and the Caton feeling is serious. The main reason for the Caton feeling is that the DOM structure will be modified in each loop, and the execution time of the loop is too long and the rendering frame rate of the browser is too low due to the large amount of data.
In fact, with a long list of 100000 li, users will not see all at once, but only a few. Therefore, we can delay the completion of most li rendering work.
We can reduce the blocking time of the main thread from two aspects: reducing the number of DOM operations and shortening the cycle time.
DocumentFragment
The DocumentFragment interface represents a minimal document object that has no parent. It is used as a lightweight version of Document that stores a segment of a document structure comprised of nodes just like a standard document. The key difference is that because the document fragment isn't part of the active document tree structure, changes made to the fragment don't affect the document, cause reflow, or incur any performance impact that can occur when changes are made.In the introduction of MDN, we know that we can reduce the number of DOM operations and the impact of backflow on performance through the use of DocumentFragment.
requestAniminationFrame
The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint.In terms of shortening the cycle time, we can insert 100000 li into the page in batches through the idea of "divide and conquer", and we can insert new nodes before page redrawing through requestanimation frame.
Event binding
If we want to listen to massive elements, the recommended method is to use the event mechanism of "JavaScript" to implement event delegation, which can significantly reduce the number of DOM event registrations.
Guangzhou design companyhttps://www.houdianzi.com My 007 office resources websitehttps://www.wode007.com
Solution
After the above discussion, we have the following solutions.
(function() { const ulContainer = document.getElementById("list-with-big-data"); // Defensive Programming if (!ulContainer) { return; } const total = 100000; // Total number of inserted data const batchSize = 4; // The number of nodes inserted in batch each time. The more the number, the more stuck the interface const batchCount = total / batchSize; // Number of batches let batchDone = 0; // Number of batches completed function appendItems() { // Use DocumentFragment to reduce the number of DOM operations and do not reflow existing elements const fragment = document.createDocumentFragment(); for (let i = 0; i < batchSize; i++) { const liItem = document.createElement("li"); liItem.innerText = batchDone * batchSize + i + 1; fragment.appendChild(liItem); } // The DOM is modified only once per batch ulContainer.appendChild(fragment); batchDone++; doAppendBatch(); } function doAppendBatch() { if (batchDone < batchCount) { // Insert new nodes in batches before redrawing window.requestAnimationFrame(appendItems); } } // kickoff doAppendBatch(); // Use event delegation and JavaScript event mechanism to realize the monitoring of massive elements and effectively reduce the number of event registration ulContainer.addEventListener("click", function(e) { const target = e.target; if (target.tagName === "LI") { alert(target.innerText); } }); })();