Why is documentFragment no faster than repeated DOM access?

前端 未结 2 2154
忘掉有多难
忘掉有多难 2021-02-15 01:56

I was always under the impression that rather than touching the DOM repeatedly, for performance reasons, we should use a documentFragment to append multiple element

2条回答
  •  心在旅途
    2021-02-15 02:36

    Well actually your test code just insert nodes and do not alter their content or CSS which would in fact force the rendering engine to a reflow.

    I have prepared 3 tests to demonstrate this dramatic difference.

    1. Simple DOM modificiation resulting Layout Trashing
    2. Simple DOM modificiation through window.requestAnimationFrame()
    3. Virtual DOM modification through document.createDocumentFragment()

    Notes:

    • You might like to test on full screen.
    • In Firefox I have obtained even more dramatic results.

    // Resets the divs
    function resetLayout() {
      divs = document.querySelectorAll('div');
      speed.textContent = "Resetting Layout...";
      setTimeout(function() {
                   each.call(divs, function(div) {
                                     div.style.height = '';
                                     div.offsetTop;
                                   });
                   speed.textContent = "";
                 }, 16);
    }
    // print the result
    function renderSpeed(ms) {
      speed.textContent = ms + 'ms';
    }
    
    var divs        = document.querySelectorAll('div'),
        raf         = window.requestAnimationFrame,
        each        = Array.prototype.forEach,
        isAfterVdom = false,
        start       = 0;
    
    // Reset the Layout
    
    reset.onclick = resetLayout;
    
    // Direct DOM Access
    
    direct.onclick = function() {
                       isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                       start = performance.now();
    
                       each.call(divs, function(div) {
                       var width = div.clientWidth;
                       div.style.height = ~~(Math.random()*2*width+6) + 'px';
                       div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                     });
    
                       // Render result
                       renderSpeed(performance.now() - start);
                     };
    
    // Access DOM at the next frame by requestAnimationFrame
    
    rAF.onclick = function() {
                    isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                    start = performance.now();
    
                    each.call(divs, function(div) {
                                      var width = div.clientWidth;
                                      // Schedule the write operation to be run in the next frame.
                                      raf(function() {
                                            div.style.height = ~~(Math.random()*2*width+6) + 'px';
                                            div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                                          });
                                    });
                   // Render result
                   raf(function() {
                         renderSpeed(performance.now() - start);
                       });
                 };
    
    // Update the vDOM and access DOM just once by rAF
    
    vdom.onclick = function() {
                     var sectCl = divCompartment.cloneNode(true),
                         divsCl = sectCl.querySelectorAll('div'),
                         dFrag  = document.createDocumentFragment(),
                         width  = divCompartment.querySelector('div').clientWidth;
                     
                     isAfterVdom = true;
                     end = 0;
                     start  = performance.now();
                     each.call(divsCl, function(div) {
                                         div.style.height = ~~(Math.random()*2*width+6) + 'px';
                                         div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                                       });
                     dFrag.appendChild(sectCl);
                     divCompartment.parentNode.replaceChild(dFrag, divCompartment);
                     // Render result
                     renderSpeed(performance.now() - start);
                   };
    html {
      font: 14px Helvetica, sans-serif;
      background: black;
      color: white;
    }
    
    * {
      box-sizing: border-box;
      margin-bottom: 1rem;
    }
    
    h1 {
      font-size: 2em;
      //word-break: break-word;
      -webkit-hyphens: auto;
    }
    
    button {
      background-color: white;
    }
    
    div {
      display: inline-block;
      width: 5%;
      margin: 3px;
      background: white;
      border: solid 2px white;
      border-radius: 10px
    }
    
    section {
      overflow: hidden;
    }
    
    #speed {
      font-size: 2.4em;
    }
    
      

    Updating 1000 DOM Nodes

提交回复
热议问题