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:
  1. To create adomNode, and not in the masterdomTree, simply understood as “virtualdom“; And insert intodomIn the tree, only the descendants of the virtual node will appear, which is trueThings brushed clothes go, deep and name
  2. 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:

  1. requestAnimationFrameIt’s going to take all of the framesDOMThe 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.
  2. In hidden or invisible elements,requestAnimationFrameThere will be no repainting or reflow, which of course means lesscpu.gpuAnd 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

conclusion

You think it helps, give it a “like” before you leave. Welcome big guy to correct, arrange ~

Contributions from:Learn to render millions of data in minutes of front-end optimization without stalling