但为什么浏览器DOM经过十年的努力仍然如此缓慢呢?

网页浏览器DOM自90年代后期就已经出现,但它仍然是性能/速度方面最大的限制之一。

我们有来自谷歌,Mozilla,微软,Opera,W3C以及其他各种从事networking技术的机构的世界上最聪明的人,所以显然这不是一个简单的“哦,我们没有优化它“ 问题。

我的问题是,如果我正在处理专门处理这个问题的networking浏览器的一部分,为什么我会这么难以使其运行得更快?

我的问题不是是什么让它变慢,而是问为什么它变得更快?

这似乎与其他地方正在发生的事情背道而驰,比如性能接近C ++代码的JS引擎。

快速脚本示例:

for (var i=0;i<=10000;i++){ someString = "foo"; } 

由于DOM缓慢的示例:

 for (var i=0;i<=10000;i++){ element.innerHTML = "foo"; } 

根据要求提供一些细节:

在基准testing之后,看起来这不是一个无法解决的缓慢问题,但是通常使用了错误的工具,而使用的工具取决于您在跨浏览器上进行的操作。

看起来浏览器之间的DOM效率差别很大,但是我原来推测dom很慢并且无法解决似乎是错误的。

我对Chrome,FF4和IE 5-9进行了testing,您可以在此图表中看到每秒的操作:

在这里输入图像说明

Chrome在使用DOM API时闪电般快,但使用.innerHTML运算符的速度要慢得多(速度要慢1000倍),但FF在某些领域比Chrome要糟糕(例如,追加testing比Chrome),但是InnerHTMLtesting运行得比chrome快得多。

IE浏览器似乎实际上在使用DOM append时变得越来越糟糕,并且在5.5版本(即IE9中的73ops /秒,现在在IE9中为51 ops / sec)上进展时,在innerHTML上更好。

我在这里有testing页面:

http://jsperf.com/browser-dom-speed-tests2

有趣的是,看起来不同的浏览器在生成DOM时似乎都面临着不同的挑战。 为什么这里有这样的差距?

当你改变DOM中的某些东西时,可能会对重新计算布局,样式表等产生无数的副作用。

这不是唯一的原因:当你设置element.innerHTML=x你不再需要处理普通的“在这里存储一个值”的variables,而是用设置它们时在浏览器中更新内部状态负载的特殊对象。

element.innerHTML=x的全部含义是巨大的。 粗略的概述:

  • xparsing为HTML
  • 请求浏览器扩展许可
  • 销毁element现有子节点
  • 创build子节点
  • 重新计算根据父子关系定义的样式
  • 重新计算页面元素的物理尺寸
  • 通知浏览器扩展的变化
  • 更新作为真正DOM节点的句柄的Javascriptvariables

所有这些更新都必须通过一个桥接Javascript和HTML引擎的API。 现在JavaScript的速度如此之快的一个原因是,我们把它编译成一些更快的语言,甚至是机器代码,因为值的行为是明确的,所以发生了大量的优化。 当通过DOM API工作时,这是不可能的。 其他地方的加速器已经把DOM留下了。

首先,你对DOM做的任何事情都可能是用户可见的变化。 如果您更改DOM,则浏览器必须再次放下所有内容。 如果浏览器caching更改,则可能会更快,然后每隔X毫秒(假设它已经不这样做),但可能对此类function的需求不大。

其次,innerHTML不是一个简单的操作。 这是MS推动的一个肮脏的黑客攻击,其他浏览器因为它非常有用而被采用。 但它不是标准(IIRC)的一部分。 使用innerHTML,浏览器必须parsingstring,并将其转换为DOM。 parsing很难。

原来的testing作者是Hixie( http://nontroppo.org/timer/Hixie_DOM.html )。

这个问题已经在这里讨论了StackOverflow和Connect(bug-tracker) 。 用IE10,问题就解决了。 通过解决,我的意思是他们已经部分转移到另一种更新DOM的方式。

IE团队似乎在处理类似于微软的Excel-macros团队的DOM更新,在那里被认为是一个糟糕的做法来更新工作表上的活动单元格。 作为开发人员,您应该离线完成繁重的任务,然后批量更新现场团队。 在IE中,你应该使用document-fragment(而不是文档)。 随着新出现的ECMA和W3C标准,文件碎片被折旧。 所以IE团队已经做了一些漂亮的工作来解决这个问题。

他们花了几个星期的时间从IE10-ConsumerPreview的约42,000毫秒降低到约600毫秒的IE10-RTM 。 但花了很多力气说服他们这是一个问题。 他们的说法是没有真实的例子,每个元素有10,000个更新。 由于富互联网应用程序(RIA)的范围和性质无法预测,因此其performance与联盟其他浏览器的performance接近。 这里是MS上的另一个关于DOM的操作(注释):

当我浏览到http://nontroppo.org/timer/Hixie_DOM.html时; ,大约需要680ms,如果我保存页面并在本地运行,则需要〜350ms!

同样的事情发生,如果我使用button-onclick事件来运行脚本(而不是body-onload)。 比较这两个版本:

jsfiddle.net/uAySs/ < – body onload

jsfiddle.net/8Kagz/ < – button onclick

差不多有两倍

显然,onload和onclick的潜在行为也会有所不同。 未来的更新可能会更好。