Javascript 重新计算风格:为什么如此口吃?
假设我们有一个将一系列类似元素注入DOM的代码。大概是这样的:Javascript 重新计算风格:为什么如此口吃?,javascript,css,performance,google-chrome,Javascript,Css,Performance,Google Chrome,假设我们有一个将一系列类似元素注入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('u
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);
在Firefox(25.0)中运行此代码段时,调用“inject”和实际查看其结果之间的时间与time/timeEnd
记录的时间相对应。对于1000个元素,约4ms;对于10000,大约40,等等。很正常,不是吗
然而,使用Chrome(测试了30.0和32.0)。虽然报告的处理和附加时间实际上少于Firefox,但呈现这些元素需要更多的时间
困惑不解的是,我检查了Chrome的探查器的不同场景,结果发现瓶颈在于重新计算风格的操作。10000个节点需要2-3秒,20000个节点需要8秒,30000个节点需要17秒
现在真正的问题是:有没有人也遇到过同样的情况,有没有解决办法
我们考虑过的一种可能的方法是限制这些节点在某种惰性负载中的可见性(“一种”,因为它更多的是关于“惰性显示”:元素已经就位,只有它们的可见性会受到限制)。已经确认,“重新计算样式”仅在元素即将变为可见时触发(这实际上是有意义的)。看起来问题在于
li
元素具有显示:列表项
如果您使用div
元素而不是ul
/li
,它在chrome中运行得非常快
另外,创建li{display:block;}
的css规则可以修复延迟
手动添加列表项
会显示延迟,即使元素已经在DOM中呈现(当然它们必须重新呈现)
请参见演示
(因此,chrome在呈现display:list item
元素方面似乎很慢)
还有一个相关的bug提交到chrome中,它已经被合并到(看起来在早期版本中它是崩溃chrome的,但它已经被修复。崩溃,而不是速度)chrome曾经是最好的浏览器。如今,情况并非如此。其他浏览器已经赶上了Chrome,谷歌显然把重点放在了手持设备的Chrome上。旁注:你似乎喜欢一些技巧:我会使用较短的
Object.keys(Array.apply(0,Array(COUNT))
而不是Object.keys(Array(COUNT).join(',).split(',)
,我想我应该把它作为一个评论而不是一个答案,因为它是推测性的:我认为许多浏览器已经优化了“appendChild”,以便在单个元素中添加少量节点。但是,您可能想尝试用“内NHTML”进行同样的测试,这更可能在C++代码中进行优化,以便同时添加大量的HTML块;比如当你加载一个巨大的页面时会发生什么。在添加javascript时,您试图自己处理浏览器的工作。(innerHTML对于一些小的添加/更改来说确实有些过头了)@Katana314。这非常有帮助,谢谢!我想我应该为此提交一份bug报告-至少我看不到任何合理的解释,为什么应该以不同的方式处理列表项
元素。@Raina77现在它们确实与其他元素有一些本质的区别,例如通过我假设的CSS计数器(用于ol
元素的数字)进行的项目符号/数字装饰,但是禁用这些功能没有什么区别,所以问题出在其他地方。。