我的网页在(批量)紧密循环中一次创建批次 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,但我的应用程序必须与旧浏览器兼容,所以不幸的是它不是一个选项。 :(
答案 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')
}
答案 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不会被锁定。