chrome“appendChild”真的那么慢吗?
Posted
技术标签:
【中文标题】chrome“appendChild”真的那么慢吗?【英文标题】:Is chromes "appendChild" really that slow? 【发布时间】:2012-02-13 08:47:25 【问题描述】:我有一个完全使用document.createElement
和document.appendChild
生成应用程序DOM 的框架。现在应用程序变得越来越大,我注意到 Chrome 与其他浏览器一样需要更长的时间来构建 DOM。
所以,我创建了以下性能测试:
window.onload = function()
var now = new Date().getTime();
for(var i = 0; i < 10000; i++)
document.body.appendChild(document.createElement("div"));
setTimeout(function()
console.log(new Date().getTime() - now);
,0);
这个测试的结果很有意思:
铬 16:700+ 火狐9:560 IE 9:210 Opera 11.60: 51Chrome 的完成时间是 Opera 的 14 倍多。 这不仅仅是一个毫无意义的基准!我真的可以在我的应用中感受到这种不同。
Chrome 在 DOM 操作上这么慢是正常的吗? 有没有办法加快速度?
谢谢!
【问题讨论】:
setTimeout
似乎会耽误你的时间。
@Domenic 你需要 setTimeout 在这种基准测试中,以便浏览器在你得到时间之前确实可以工作
@Esailija 不正确,正如我的性能测试所示,它让你失望:jsperf.com/appendchild-from-so 回想一下,setTimeout
在不同的浏览器中被限制为不同的值。
@Domenic jsperf 有什么相关性?无论如何:jsfiddle.net/rZzYk/2
@Domenic 但它返回正确的结果,您至少可以使用时间线工具在 chrome 中验证。根据时间轴,渲染耗时 3.04 秒,但第一个记录的数字是 600 毫秒。那是因为浏览器仅在记录该时间后才呈现。如果您将日志记录推迟到线程空闲后立即进行(即setTimeout( , 0)
,您将获得渲染完成后的时间。
【参考方案1】:
更新 2
这是一种骇人听闻的解决方案,可能值得进行一点浏览器检测。它使我的测试性能降低到不到原来的 1/10。
你可以在追加之前display='none'
容器,之后再显示。你可能会得到一点闪光,但这可能比长时间的延迟要好。
window.onload = function()
var content = String.fromCharCode(Math.floor(Math.random() * 1000));
// cache it in case it is already set
var disp = document.body.style.display;
document.body.style.display = 'none';
var now = new Date().getTime();
for(var i = 0; i < 10000; i++)
document.body.appendChild(document.createElement("div"))
.appendChild(document.createTextNode( content ));
setTimeout(function()
console.log(new Date().getTime() - now);
document.body.style.display = disp || ''; // restore it
,0);
;
这是我对documentFragment
的预期性能提升。
更新
在运行 modified version 的 @Esailija's jsFiddle 测试以包含 documentFragment 之后,它似乎在 Chrome(或 Opera 中)没有任何区别,因此它显示为虽然 Chrome 更慢。
“有没有办法加快速度?”
我猜如果您使用 documentFragment
,然后使用单个 .appendChild
附加到 DOM,您将获得更好的性能。
window.onload = function()
var now = new Date().getTime();
// create a documentFragment
var frag = document.createDocumentFragment();
for(var i = 0; i < 10000; i++)
frag.appendChild(Div()); // append to the documentFragment
// append the documentFragment (which is emptied)
document.body.appendChild(frag);
setTimeout(function()
console.log(new Date().getTime() - now);
,0);
function Div()
var This = document.createElement("div");
return This;
【讨论】:
使用 documentFragment 会极大地加速它,或者任何不属于 DOM 的容器。我猜 Opera 在“幕后”做这件事,这并不总是预期的行为。 您的更新是正确的,使用您的代码并不能真正加快速度。有区别,但只有50ms左右...我仍然认为应该有解决方案...:S @VanCoding:考虑到大部分时间来自页面重绘,我不知道你是否真的能够改变它。如果您希望避免浏览器出现冻结,您可以将任务分解为更小的异步块,以允许用户仍然与页面交互。除此之外,我不知道你能做些什么来提高 Chrome 的重绘性能。这在引擎盖下很好。 是的。我会将此作为错误报告给 chrome 开发团队。 @VanCoding:我为你准备了一个骇人听闻的解决方案。如果你在循环之前执行document.body.style.display = 'none';
,那么在setTimeout
执行...display = ''
,性能似乎完全消除了重绘性能。我会更新的。【参考方案2】:
我觉得这很正常……
html 对象操作(宽度、高度和不透明度)也是如此,尤其是在您使用 CSS3 时。
我编写了一个幻灯片(不使用 jQuery,我讨厌它),它在 FF、IE、Opera、Safari 中运行顺利……但在 Chomre 中却没有。在 Chrome 中,速度慢得令人难以置信(仅在较新的 Chrome 版本中,在 v12 等旧版本中速度更快)。
【讨论】:
【参考方案3】:您的测试似乎有缺陷。如果你做一个纯粹的appendChild
测试,Chrome 会遥遥领先:
http://jsperf.com/appendchild-from-so
【讨论】:
只对 appendChild 的调用进行基准测试是不够的!调用本身确实很快,但是在JS进入idle之后,chrome还有很多事情要做,才能开始下一个tick。在所有其他浏览器中,这似乎有所不同。但是:我想对整个过程进行基准测试,包括所有处理时间。以上是关于chrome“appendChild”真的那么慢吗?的主要内容,如果未能解决你的问题,请参考以下文章