【发布时间】:2013-11-16 17:51:39
【问题描述】:
假设我们有一个将一系列相似元素注入 DOM 的代码。像这样的:
var COUNT = 10000,
elements = Object.keys(Array(COUNT).join('|').split('|'));
var d = document,
root = d.getElementById('root');
function inject() {
var count = COUNT,
ul = d.createElement('ul'),
liTmpl = d.createElement('li'),
liEl = null;
console.time('Processing elements');
while (count--) {
liEl = liTmpl.cloneNode(false);
liEl.textContent = elements[count];
ul.appendChild(liEl);
}
console.timeEnd('Processing elements');
console.time('Appending into DOM');
root.appendChild(ul);
console.timeEnd('Appending into DOM');
};
d.getElementById('inject').addEventListener('click', inject);
Demo.
当这个 sn-p 在 Firefox (25.0) 中运行时,调用 'inject' 和实际看到它的结果之间的时间与time/timeEnd 记录的时间相对应。对于 1000 个元素,大约 4 ms; 10000,大约 40 等等。很正常,不是吗?
但是,对于 Chrome(30.0 和 Canary 32.0 已测试),情况并非如此。虽然报告的处理和附加时间实际上少于 Firefox,但渲染这些元素需要更多时间。
困惑的是,我检查了 Chrome 的分析器以了解不同的场景 - 结果发现瓶颈在于重新计算样式操作。 10000个节点需要2-3秒,20000个节点需要8秒,30000个节点需要17秒。
现在真正的问题是:有没有人遇到过同样的情况,有什么解决方法吗?
我们考虑过的一种可能的方法是将这些节点的可见性限制在一种延迟加载中(“一种”,因为它更多的是“延迟显示”:元素已经就位,只有它们的能见度将受到限制)。确认“重新计算样式”仅在元素即将变得可见时触发(实际上这是有道理的)。
【问题讨论】:
-
Chrome 曾经是最好的浏览器。如今,没有那么多。其他浏览器已经赶上了 Chrome,而 Google 显然已经将重点放在了适用于手持设备的 Chrome 上。
-
旁注,因为您似乎喜欢技巧:我会使用较短的
Object.keys(Array.apply(0,Array(COUNT)))而不是Object.keys(Array(COUNT).join(',').split(','))。 -
好吧,我想我应该把它作为评论而不是答案,因为它是推测性的:我认为许多浏览器已经优化了“appendChild”,以便将少量节点添加到单个元素。但是,您可能想尝试使用“innerHTML”进行相同的测试——这更有可能在 C++ 代码中进行了优化,以便一次添加大量 HTML;就像当你加载一个巨大的页面时会发生什么。使用 javascript 附加所有内容时,您正在尝试自己处理浏览器的工作。 (不过,对于小的添加/更改,innerHTML 确实是矫枉过正)
-
@Katana314 I tested.
标签: javascript css performance google-chrome