Implementation of loading massive data on html page

subject

The array of 10w records is rendered to the page at one time. How to deal with it without freezing the UI?  
 

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);
    }
  });
})();

Tags: Front-end

Posted by tomhoad on Wed, 11 May 2022 08:46:56 +0300