Javascript 但为什么';经过10年的努力,浏览器DOM还是那么慢吗?

Javascript 但为什么';经过10年的努力,浏览器DOM还是那么慢吗?,javascript,dom,Javascript,Dom,web浏览器DOM自90年代末就已经存在,但它仍然是性能/速度方面的最大限制之一 谷歌、Mozilla、微软、Opera、W3C和其他各种组织都有世界上最聪明的头脑,他们为我们所有人研究网络技术,所以显然这不是一个简单的“哦,我们没有优化它”问题 我的问题是如果我在一个专门处理这个问题的web浏览器上工作,为什么我会很难让它运行得更快 我的问题不是问会让它变慢,而是问会不会变快 这似乎与其他地方发生的事情有冲突,比如JS引擎,性能接近C++代码。 快速脚本示例: for (var i=0;i&l

web浏览器DOM自90年代末就已经存在,但它仍然是性能/速度方面的最大限制之一

谷歌、Mozilla、微软、Opera、W3C和其他各种组织都有世界上最聪明的头脑,他们为我们所有人研究网络技术,所以显然这不是一个简单的“哦,我们没有优化它”问题

我的问题是如果我在一个专门处理这个问题的web浏览器上工作,为什么我会很难让它运行得更快

我的问题不是问会让它变慢,而是问会不会变快

这似乎与其他地方发生的事情有冲突,比如JS引擎,性能接近C++代码。 快速脚本示例:

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

for(var i=0;i当您在DOM中更改某些内容时,可能会产生大量的副作用,与重新计算布局、样式表等有关

这不是唯一的原因:当您设置
element.innerHTML=x
时,您不再处理普通的“在此处存储值”变量,而是处理特殊对象,这些对象在您设置它们时会更新浏览器中的内部状态

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

  • x
    解析为HTML
  • 请求浏览器扩展以获得许可
  • 销毁
    元素的现有子节点
  • 创建子节点
  • 重新计算根据父子关系定义的样式
  • 重新计算页面元素的物理尺寸
  • 将更改通知浏览器扩展
  • 更新作为实际DOM节点句柄的Javascript变量

所有这些更新都必须通过一个连接Javascript和HTML引擎的API。如今Javascript速度如此之快的一个原因是我们将其编译为更快的语言甚至机器代码,大量优化发生,因为值的行为定义良好。在使用DOM API时,none这是可能的。其他地方的加速已经将DOM抛在了后面。

首先,您对DOM所做的任何更改都可能是用户可见的更改。如果您更改DOM,浏览器必须重新布局所有内容。如果浏览器缓存更改,则只需每隔X ms进行一次布局(假设它还没有这样做),速度可能会更快,但对这种功能的需求可能不是很大


其次,innerHTML不是一个简单的操作。它是微软推出的一个肮脏的黑客,其他浏览器之所以采用它是因为它非常有用;但它不是标准(IIRC)的一部分。使用innerHTML,浏览器必须解析字符串,并将其转换为DOM。解析很困难。

最初的测试作者是Hixie()

这个问题已经在和上讨论过了。通过IE10,这个问题已经解决了。通过解决,我的意思是他们已经部分地转向了另一种更新DOM的方式

IE团队似乎处理DOM更新的方式与Microsoft的Excel宏团队类似,在Microsoft中,更新工作表上的活动单元格被认为是一种糟糕的做法。作为开发人员,您应该将繁重的任务脱机,然后批量更新活动团队。在IE中,您应该使用文档片段进行更新(与文档相反)。随着新出现的ECMA和W3C标准的出现,文档碎片被贬低了。所以IE团队已经做了一些很好的工作来解决这个问题

他们花了几周时间才将其从IE10 ConsumerView中的42000毫秒缩减到600毫秒IE10-RTM。但他们花了很多时间才说服他们这是一个问题。他们声称,在现实世界中没有一个每个元素有10000次更新的例子。因为富互联网应用程序(RIA)的范围和性质无法预测,它的性能接近联盟中的其他浏览器是至关重要的。下面是MS Connect上OP对DOM的另一个看法(在评论中):

当我浏览到时,它需要 ~680毫秒,如果我保存页面并在本地运行,则需要~350毫秒

如果使用button onclick事件运行脚本,也会发生同样的情况 (而不是车身加载)。比较这两种版本:


jsfiddle.net/uAySs/我之所以发表评论,是因为我不知道,但我怀疑这是因为每次您更改某些内容时它都必须更新。Delphi的TListView也是如此-如果您在For循环中添加1000项,而不首先调用
Listview.BeginUpdate;
,那么它将非常缓慢,并且会消耗内存。但是,如果您确实调用BeginUpdate fir在调用endUpdate之前,它不会再次尝试重新绘制。看在上帝的份上,用Firefox2和Firefox8之间差异的一些数据和基准来支持这一点,并向我们展示DOM是缓慢的。exGoogler发布了一篇关于DOM布局为何如此缓慢的帖子:。关于业余爱好者的相关帖子:
for (var i=0;i<=10000;i++){
    element.innerHTML = "foo";
}