An array of 10w records is rendered to the page at one time. How to deal with it without freezing the UI?
Specification
There is an empty unordered list node ul on the page, whose id is list-with-big-data. Now we need to insert 10w li into the list. The text content of each list item can be defined by itself, and we need to display the text content of 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> web Front-end development learning Q-q-u-n: 784783012 ,Share learning methods and small details, keep updating the latest teaching and learning methods
Analysis
Perhaps at the first glance of this problem, we may think of such a solution: get ul elements, then create new li elements, set up the text content of li and listener binding, and then append ul in the loop, which may be thought of as the following code implementation.
(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; // this of the EventListener callback function defaults to the current node, so be careful if you use the arrow function liItem.addEventListener("click", function() { alert(this.innerText); }); ulContainer.appendChild(liItem); } })(); //Copy code
Practicing the above code, we found that the interface experience was very unfriendly and Carton felt serious. The main reason for the sense of cartoon is that DOM structure is modified in every cycle, and because of the large amount of data, the execution time of the loop is too long and the rendering frame rate of browser is too low.
In fact, with a long list of 100,000 li, users won't see all of it immediately, but only a few of it. Therefore, we can delay the rendering of most li.
We can reduce the blocking time of the main thread by reducing the number of DOM operations and 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 the use of Document Fragment can reduce the number of DOM operations and reduce the impact of reflux on performance.
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 100,000 li into the page in batches through the idea of divide and conquer, and we can insert new nodes before redrawing the page through the request Animination Frame.
Event binding
If we want to listen for massive elements, the recommended method is to use JavaScript event mechanism to implement event delegation, which can significantly reduce the number of DOM event registrations.
Solution
After the discussion above, 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 more nodes are inserted in batches, the more jammed the interface is. const batchCount = total / batchSize; // Number of batches let batchDone = 0; // Number of batches completed function appendItems() { // Use Document Fragment to reduce DOM operations and 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); } // Modify DOM only once per batch ulContainer.appendChild(fragment); batchDone++; doAppendBatch(); } function doAppendBatch() { if (batchDone < batchCount) { // Before redrawing, insert new nodes in batches window.requestAnimationFrame(appendItems); } } // kickoff doAppendBatch(); // Using event delegation and JavaScript event mechanism, we can monitor 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); } }); })(); web Front-end development learning Q-q-u-n: 784783012 ,Share learning methods and small details, keep updating the latest teaching and learning methods