technology-blog icon indicating copy to clipboard operation
technology-blog copied to clipboard

第 15 题:1000-div问题

Open airuikun opened this issue 6 years ago • 13 comments

  • 一次性插入1000个div,如何优化插入的性能
    • 使用Fragment
    var fragment = document.createDocumentFragment();
    fragment.appendChild(elem);
  • 向1000个并排的div元素中,插入一个平级的div元素,如何优化插入的性能
    • 先display:none 然后插入 再display:block
    • 赋予key,然后使用virtual-dom,先render,然后diff,最后patch
    • 脱离文档流,用GPU去渲染,开启硬件加速

airuikun avatar Apr 14 '19 08:04 airuikun

var oFrag=document.createDocumentFragment();

for(var i=0;i<1000;i++){ var op=document.createElement("div"); var oText=document.createTextNode(‘i’); op.appendChild(oText); oFrag.appendChild(op); } document.body.appendChild(oFrag);

Lanveer avatar Apr 15 '19 08:04 Lanveer

应该先创建一个div,后续的复制这个元素,避免重复创建元素,再放到元素片段里面 var divFragment=document.createDocumentFragment(); let div=document.createElement("div"); for(var i=0;i<1000;i++){ divFragment.append(div.cloneNode()) } document.body.appendChild(divFragment);

lvruiyang avatar Apr 18 '19 08:04 lvruiyang

在chrome浏览器上试了下,使用fragment比不用反而更慢点呢..

应该是现代浏览器有针对这方面做优化了。所以,并不需要用 var fragment = document.createDocumentFragment(); fragment.appendChild(elem); 这种方式了吧 ?

chen4342024 avatar Apr 18 '19 09:04 chen4342024

使用 requestAnimationFrame 分片插入

mochen666 avatar Apr 18 '19 11:04 mochen666

其实js操作字符串比操作对象高效的多。我觉得这是最高效也是最快的。

let _html = '';
for(var i=0;i<1000;i++){
   _html += '<div></div>';
}
ElementObj.innerHTML= _html;

yexk avatar Apr 22 '19 01:04 yexk

其实js操作字符串比操作对象高效的多。我觉得这是最高效也是最快的。

let _html = '';
for(var i=0;i<1000;i++){
   _html += '<div></div>';
}
ElementObj.innerHTML= _html;

用代码跑了一遍,实际上并没有比直接插入快 。 我也有点疑惑``

        let loopNum = 5000;
        console.time("handleNormalAppendDiv");
        for (var i = 0; i < loopNum; i++) {
            var op = document.createElement("div");
            containerEl.appendChild(op);
        }
        console.timeEnd("handleNormalAppendDiv");

        console.time("handleStringAppendDiv");
        let html = "";
        for (var i = 0; i < loopNum; i++) {
            html += "<div></div>";
        }
        var op = document.createElement("div");
        op.innerHTML = html;
        containerEl.appendChild(op);
        console.timeEnd("handleStringAppendDiv");

`` 结果输出: handleNormalAppendDiv: 5.595947265625ms handleStringAppendDiv: 6.323974609375ms

chen4342024 avatar Apr 22 '19 02:04 chen4342024

其实js操作字符串比操作对象高效的多。我觉得这是最高效也是最快的。

let _html = '';
for(var i=0;i<1000;i++){
   _html += '<div></div>';
}
ElementObj.innerHTML= _html;

用代码跑了一遍,实际上并没有比直接插入快 。 我也有点疑惑``

        let loopNum = 5000;
        console.time("handleNormalAppendDiv");
        for (var i = 0; i < loopNum; i++) {
            var op = document.createElement("div");
            containerEl.appendChild(op);
        }
        console.timeEnd("handleNormalAppendDiv");

        console.time("handleStringAppendDiv");
        let html = "";
        for (var i = 0; i < loopNum; i++) {
            html += "<div></div>";
        }
        var op = document.createElement("div");
        op.innerHTML = html;
        containerEl.appendChild(op);
        console.timeEnd("handleStringAppendDiv");

`` 结果输出: handleNormalAppendDiv: 5.595947265625ms handleStringAppendDiv: 6.323974609375ms

你这个操作不对吧。。你还多了创建了一级dom。时间当然多了。 handleNormalAppendDiv生成应该是dom>dom5000 handleStringAppendDiv生成的应该是dom>dom>dom5000

看我codepen的demo吧。可以证明我是对的。我的结论是 string < fragment < normal (根据耗时排序) https://codepen.io/yexk/pen/KYBKMR 2019-04-22_113720 (ps:多测试几次)

yexk avatar Apr 22 '19 03:04 yexk

其实js操作字符串比操作对象高效的多。我觉得这是最高效也是最快的。

let _html = '';
for(var i=0;i<1000;i++){
   _html += '<div></div>';
}
ElementObj.innerHTML= _html;

用代码跑了一遍,实际上并没有比直接插入快 。 我也有点疑惑``

        let loopNum = 5000;
        console.time("handleNormalAppendDiv");
        for (var i = 0; i < loopNum; i++) {
            var op = document.createElement("div");
            containerEl.appendChild(op);
        }
        console.timeEnd("handleNormalAppendDiv");

        console.time("handleStringAppendDiv");
        let html = "";
        for (var i = 0; i < loopNum; i++) {
            html += "<div></div>";
        }
        var op = document.createElement("div");
        op.innerHTML = html;
        containerEl.appendChild(op);
        console.timeEnd("handleStringAppendDiv");

`` 结果输出: handleNormalAppendDiv: 5.595947265625ms handleStringAppendDiv: 6.323974609375ms

你这个操作不对吧。。你还多了创建了一级dom。时间当然多了。 handleNormalAppendDiv生成应该是dom>dom_5000 handleStringAppendDiv生成的应该是dom>dom>dom_5000

看我codepen的demo吧。可以证明我是对的。我的结论是 string < fragment < normal (根据耗时排序) https://codepen.io/yexk/pen/KYBKMR 2019-04-22_113720 (ps:多测试几次)

试了几次,string和normal的确会有波动 。 不过,按你截图的结果: 大概率是 string < normal < fragment 。 fragment大概率是耗时最长的呀。而不是排中间

chen4342024 avatar Apr 22 '19 03:04 chen4342024

感觉这里提到的性能优化, 并不是单单指 dom 渲染耗时, 也包含 dom 回流和重绘, 如果是全部 append 肯定会执行至少 1000次回流甚至还有重绘, 所以 string 和 fragment 应该性能比较好, 但如何检测呢?

claudewowo avatar May 05 '19 14:05 claudewowo

function getDiv(num) {
  return '<div></div>'.repeats(num);
}

function insert(times, container) {
 if (times > 0) {
  let temp = times - 10 > 0 ? times - 10 : times;
  container.innerHTML += getDiv(temp);
 setTimeout(() => {
   insert(times - 10, container);
  }, 200);
 }
}

需要给浏览器间歇时间,这样浏览器会自行对js代码JIT以及对reflow等优化,否则来不及优化。

wbcs avatar May 14 '19 03:05 wbcs

在chrome浏览器上试了下,使用fragment比不用反而更慢点呢..

应该是现代浏览器有针对这方面做优化了。所以,并不需要用 var fragment = document.createDocumentFragment(); fragment.appendChild(elem); 这种方式了吧 ?

我测试的也是这样的 两者没太大区别

fariellany avatar May 26 '20 03:05 fariellany

其实js操作字符串比操作对象高效的多。我觉得这是最高效也是最快的。

let _html = '';
for(var i=0;i<1000;i++){
   _html += '<div></div>';
}
ElementObj.innerHTML= _html;

这个方式比操作DOM的成本更低一些

JaykeyGuo avatar Oct 25 '20 03:10 JaykeyGuo