JS性能:一次创建大量元素

时间:2013-03-09 22:02:32

标签: javascript jquery performance

我的网页在(批量)紧密循环中一次创建批次 DOM元素,具体取决于我的Comet网络服务器提供的数据。

我尝试了几种方法来创建这些元素。基本上它归结为(1):

var container = $('#selector');
for (...) container.append('<html code of the element>');

或(2):

var html = '';
for (...) html += '<html code of the element>';
$('#selector').append(html);

或(3):

var html = [];
for (...) html.push('<html code of the element>');
$('#selector').append(html.join(''));

性能方面,(1)非常糟糕(桌面计算机上每批3s,Galaxy Note fondleslab上高达500万),(2)和(3)大致相当(桌面上300ms,1.5s)在fondleslab)。这些时间约为4000个元素,大约是我预期的1/4,这是不可接受的,因为我应该在1s以下处理这个数据量(15k元素),即使在fondleslab上也是如此。

事实上(2)和(3)具有相同的性能使我认为我正在打击臭名昭着的“天真连接的字符串无用地重新分配并复制大量内存”问题(即使我期望{{ 1}}比那更聪明)。 [编辑:在仔细研究之后,碰巧我被误导了,渲染方面的问题更多 - 感谢DanC]

在C ++中,我只使用join()std::string::reserve()来避免无用的重新分配,但我不知道如何在Javascript中执行此操作。

知道如何进一步提高性能吗?或者至少指出了识别瓶颈的方法(尽管我很确定它是字符串连接)。我当然不是Javascript大师...

感谢您阅读。


对于它的价值而言,大量的元素是因为我正在使用DIV绘制(主要是实时)图形。我很清楚Canvas,但我的应用程序必须与旧浏览器兼容,所以不幸的是它不是一个选项。 :(

2 个答案:

答案 0 :(得分:2)

使用DOM方法,在我的双核MacBook上构建和附加大约55ms的12000个元素时钟。

document.getElementById('foo').addEventListener('click', function () {
    build();
}, false);

function build() {
    console.time('build');

    var fragment = document.createDocumentFragment();

    for ( var e = 0; e < 12000; e++ ) {
        var el = document.createElement('div');
        el.appendChild(document.createTextNode(e));
        fragment.appendChild(el);
    }

    document.querySelectorAll('body')[0].appendChild(fragment);

    console.timeEnd('build') 
}

Fiddle

Resig on document.createDocumentFragment

答案 1 :(得分:1)

这不是解决性能问题的方法,而只是确保UI循环可以自由处理其他请求的方法。

您可以尝试这样的事情:

var container = $('#selector');
for (...) setTimeout(function() {container.append('<html code of the element>') };

为了提高性能,我会在构建一个更大的字符串后,在每次setTimeout次迭代后调用x。并且,我自己没有尝试过,我不确定是否会保留setTimeout次调用的顺序。如果没有,那么你可以做更多这样的事情:

var arrayOfStrings = 'each element is a batch of 100 or so elements html';
function processNext(arr, i) {
  container.append(arr[i]);
  if (i < arr.length) {
    setTimeout(function() { processNext(arr, i+1); });
  }
}
processNext(arrayOfStrings, 0);

不漂亮,但会确保在操作DOM时UI不会被锁定。