javascript 但是为什么浏览器 DOM 经过 10 年的努力仍然如此缓慢?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6817093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
But why's the browser DOM still so slow after 10 years of effort?
提问by Incognito
The web browser DOM has been around since the late '90s, but it remains one of the largest constraints in performance/speed.
Web 浏览器 DOM 自 90 年代后期就已经存在,但它仍然是性能/速度方面的最大限制之一。
We have some of the world's most brilliant minds from Google, Mozilla, Microsoft, Opera, W3C, and various other organizations working on web technologies for all of us, so obviously this isn't a simple "Oh, we didn't optimize it" issue.
我们有来自 Google、Mozilla、Microsoft、Opera、W3C 和其他各种组织的一些世界上最聪明的人才为我们所有人研究 Web 技术,所以显然这不是一个简单的“哦,我们没有优化它“ 问题。
My question isif i were to work on the the part of a web browser that deals specifically with this, why would I have such a hard time making it run faster?
我的问题是,如果我要在专门处理此问题的 Web 浏览器部分工作,为什么我会很难让它运行得更快?
My question is notasking whatmakes it slow, it's asking whyhasn't it become faster?
This seems to be against the grain of what's going on elsewhere, such as JS engines with performance near that of C++ code.
这似乎与其他地方正在发生的事情背道而驰,例如性能接近 C++ 代码的 JS 引擎。
Example of quick script:
快速脚本示例:
for (var i=0;i<=10000;i++){
someString = "foo";
}
Example of slow because of DOM:
由于 DOM 导致缓慢的示例:
for (var i=0;i<=10000;i++){
element.innerHTML = "foo";
}
Some details as per request:
根据要求的一些细节:
After bench marking, it looks like it's not an unsolvable slow issue, but often the wrong tool is used, and the tool used depends on what you're doing cross-browser.
基准测试后,看起来不是一个无法解决的慢问题,但经常使用错误的工具,使用的工具取决于您跨浏览器在做什么。
It looks like the DOM efficiency varies greatly between browsers, but my original presumption that the dom is slow and unsolvable seems to be wrong.
貌似不同浏览器的 DOM 效率差别很大,但是我原来认为 dom 慢且无法解决的假设似乎是错误的。
I ran tests against Chrome, FF4, and IE 5-9, you can see the operations per second in this chart:
我对 Chrome、FF4 和 IE 5-9 进行了测试,您可以在此图表中看到每秒的操作数:
Chrome is lightning fast when you use the DOM API, but vastly slower using the .innerHTML operator (by a magnitude 1000-fold slower), however, FF is worse than Chrome in some areas (for instance, the append test is much slower than Chrome), but the InnerHTML test runs much faster than chrome.
当您使用 DOM API 时,Chrome 快如闪电,但使用 .innerHTML 操作符时要慢得多(慢 1000 倍),但是,FF 在某些方面比 Chrome 差(例如,附加测试比Chrome),但 InnerHTML 测试的运行速度比 Chrome 快得多。
IE seems to actually be getting worse at using DOM append and better at innerHTML as you progress through versions since 5.5 (ie, 73ops/sec in IE8 now at 51 ops/sec in IE9).
从 5.5 开始,IE 似乎在使用 DOM append 方面变得更糟,而在 innerHTML 方面变得更好(即,IE8 中的 73ops/sec 现在 IE9 中的 51 ops/sec)。
I have the test page over here:
我这里有测试页:
http://jsperf.com/browser-dom-speed-tests2
http://jsperf.com/browser-dom-speed-tests2
What's interesting is that it seems different browsers seem to all be having different challenges when generating the DOM. Why is there such disparity here?
有趣的是,似乎不同的浏览器在生成 DOM 时都面临着不同的挑战。为什么这里会有这样的差距?
回答by spraff
When you change something in the DOM it can have myriad side-effects to do with recalculating layouts, style sheets etc.
当您更改 DOM 中的某些内容时,它可能会产生无数与重新计算布局、样式表等有关的副作用。
This isn't the only reason: when you set element.innerHTML=x
you are no longer dealing with ordinary "store a value here" variables, but with special objects which update a load of internal state in the browser when you set them.
这不是唯一的原因:当您设置时,您element.innerHTML=x
不再处理普通的“在此处存储值”变量,而是处理特殊对象,这些对象在您设置它们时会更新浏览器中的内部状态负载。
The full implications of element.innerHTML=x
are enormous. Rough overview:
的全部影响element.innerHTML=x
是巨大的。粗略概述:
- parse
x
as HTML - ask browser extensions for permission
- destroy existing child nodes of
element
- create child nodes
- recompute styles which are defined in terms of parent-child relationships
- recompute physical dimensions of page elements
- notify browser extensions of the change
- update Javascript variables which are handles to real DOM nodes
- 解析
x
为 HTML - 向浏览器扩展请求许可
- 销毁现有的子节点
element
- 创建子节点
- 重新计算根据父子关系定义的样式
- 重新计算页面元素的物理尺寸
- 将更改通知浏览器扩展
- 更新作为真实 DOM 节点句柄的 Javascript 变量
All these updates have to go through an API which bridges Javascript and the HTML engine. One reason that Javascript is so fast these days is that we compile it to some faster language or even machine code, masses of optimisations happen because the behaviour of the values is well-defined. When working through the DOM API, noneof this is possible. Speedups elsewhere have left the DOM behind.
所有这些更新都必须通过一个连接 Javascript 和 HTML 引擎的 API。如今 Javascript 如此之快的一个原因是我们将其编译为某种更快的语言甚至机器代码,由于值的行为是明确定义的,因此会发生大量优化。通过DOM API工作时,没有这种可能。其他地方的加速已经把 DOM 抛在了后面。
回答by wisty
Firstly, anything you do to the DOM could be a user visible change. If you change the DOM, the browser has to lay everything out again. It could be faster, if the browser caches the changes, then only lays out every X ms (assuming it doesn't do this already), but perhaps there's not a huge demand for this kind of feature.
首先,您对 DOM 所做的任何事情都可能是用户可见的更改。如果您更改 DOM,浏览器必须重新布置所有内容。它可能会更快,如果浏览器缓存更改,然后只布置每 X 毫秒(假设它还没有这样做),但也许对这种功能的需求并不大。
Second, innerHTML isn't a simple operation. It's a dirty hack that MS pushed, and other browsers adopted because it's so useful; but it's not part of the standard (IIRC). Using innerHTML, the browser has to parse the string, and convert it to a DOM. Parsing is hard.
其次,innerHTML 不是一个简单的操作。这是微软推动的一个肮脏的黑客,其他浏览器也采用了它,因为它非常有用;但它不是标准 (IIRC) 的一部分。使用innerHTML,浏览器必须解析字符串,并将其转换为DOM。解析很难。
回答by vulcan raven
Original test author is Hixie (http://nontroppo.org/timer/Hixie_DOM.html).
原始测试作者是 Hixie ( http://nontroppo.org/timer/Hixie_DOM.html)。
This issue has been discussed on StackOverflow hereand Connect (bug-tracker)as well. With IE10, the issue is resolved. By resolved, I mean they have partially moved on to another way of updating DOM.
这个问题已经在StackOverflow和Connect (bug-tracker)上讨论过。使用 IE10,问题已解决。通过已解决,我的意思是他们已经部分地转向了另一种更新 DOM 的方式。
IE team seems to handle the DOM update similar to Excel-macros team at Microsoft, where it's considered a poor practice to update the live-cells on the sheet. You, the developer, is supposed to take the heavy lifting task offline and then update the live team in batch. In IE you are supposed to do that using document-fragment (as opposed to document). With new emerging ECMA and W3C standards, document-frags are depreciated. So IE team has done some pretty work to contain the issue.
IE 团队似乎处理 DOM 更新类似于 Microsoft 的 Excel 宏团队,在那里更新工作表上的活细胞被认为是一种糟糕的做法。您,开发人员,应该将繁重的任务离线,然后批量更新实时团队。在 IE 中,你应该使用文档片段(而不是文档)来做到这一点。随着新出现的 ECMA 和 W3C 标准,文档碎片被贬值。所以 IE 团队已经做了一些很好的工作来解决这个问题。
It took them few weeks to strip it down from ~42,000 ms in IE10-ConsumerPreview to ~600 ms IE10-RTM. But it took lots of leg pulling to convince them that this IS an issue. Their claim was that there is no real-world example which has 10,000 updates per element. Since the scope and nature of rich-internet-applications (RIAs) can't be predicted, its vital to have performance close to the other browsers of the league. Here is another take on DOM by OP on MS Connect (in comments):
他们花了几周时间才将其从 IE10-ConsumerPreview 中的 ~42,000 毫秒减少到 IE10-RTM 中的 ~600 毫秒。但是花了很多时间才说服他们这是一个问题。他们声称没有真实世界的例子每个元素有 10,000 次更新。由于无法预测富互联网应用程序 (RIA) 的范围和性质,因此其性能接近联盟中的其他浏览器至关重要。这是 OP 在 MS Connect 上对 DOM 的另一种看法(在评论中):
When I browse to http://nontroppo.org/timer/Hixie_DOM.html, it takes ~680ms and if I save the page and run it locally, it takes ~350ms!
Same thing happens if I use button-onclick event to run the script (instead of body-onload). Compare these two versions:
jsfiddle.net/uAySs/ <-- body onload
vs.
jsfiddle.net/8Kagz/ <-- button onclick
Almost 2x difference..
当我浏览到http://nontroppo.org/timer/Hixie_DOM.html 时,它需要约 680 毫秒,如果我保存页面并在本地运行它,则需要约 350 毫秒!
如果我使用 button-onclick 事件来运行脚本(而不是 body-onload),也会发生同样的事情。比较这两个版本:
jsfiddle.net/uAySs/ <-- 主体加载
对比
jsfiddle.net/8Kagz/ <-- 按钮点击
几乎2倍的差异..
Apparently, the underlying behavior of onload and onclick varies as well. It may get even better in future updates.
显然,onload 和 onclick 的底层行为也各不相同。在未来的更新中它可能会变得更好。