各种 Javascript 优化项目如何影响 DOM 性能?
通过 Tracemonkey、Squirrelfish 和 V8 项目,大量 C、S 计算机科学融入了 Javascript。 这些项目(或其他项目)是否解决了 DOM 操作的性能问题,或者它们纯粹与 Javascript 计算相关?
There's a lot of capital C, capital S computer science going into Javascript via the Tracemonkey, Squirrelfish, and V8 projects. Do any of these projects (or others) address the performance of DOM operations, or are they purely Javascript computation related?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
纯 DOM 操作(getElementById/Tagname/Selector、nextChild 等)的性能不受影响,因为它们已经在纯 C++ 中。
JS 引擎的改进将如何影响性能在一定程度上取决于用于性能改进的特定技术,以及 DOM->JS 桥的性能。
前者的一个例子是 TraceMonkey 依赖于对 JS 函数的所有调用。 因为跟踪有效地内联了 JS 遇到无法内联的代码(本机代码、真正的多态递归、异常处理程序)的任何点的执行路径,因此跟踪将中止并且执行回退到解释器。 TM 开发人员正在做大量工作来提高可跟踪的代码量(包括处理多态递归),但实际上跟踪对任意本机函数(例如 DOM)的调用是不可行的。 出于这个原因,我相信他们正在考虑在 JS 中实现更多的 DOM(或者至少以 JS 友好的方式)。 也就是说,当代码可追踪时,TM 可以做得非常好,因为它可以将大多数“对象”降低为更高效和/或本机等效项(例如,使用机器整数而不是 JS Number 实现)。
JavaScriptCore(SquirrelFish Extreme 所在的地方)和 V8 有更相似的方法,因为它们都立即 JIT 所有 JS 代码并生成更具推测性的代码(例如,如果您正在执行
a*b
它们生成假设a
和b
是数字的代码,如果不是数字,则回退到异常缓慢的代码)。 与跟踪相比,这有很多好处,即您可以 JIT 所有代码,无论它是否调用本机代码/抛出异常等,这意味着单个 DOM 调用不会破坏性能。 缺点是所有代码都是推测性的 - TM将内联调用 Math.floor 等,但最好的 JSC/V8 可以做的相当于a=Math.floor(0.5 )
-> a=(Math.floor == realFloor) ? inline : Math.floor(0.5) 这在性能和内存使用方面都有成本,而且也不是特别可行。 这样做的原因是预先编译,而 TM 仅在运行后执行 JIT 代码(因此确切地知道调用了什么函数),JSC 和 V8 没有真正的基础来做出这样的假设,基本上必须猜测(目前都没有尝试)这)。 V8 和 JSC 尝试解决此问题的一件事是跟踪它们过去看到的内容并将其合并到执行路径中,两者都使用组合技术来执行此缓存,特别是在热点情况下它们重写指令流的一小部分,并且在其他情况下它们保留带外缓存。 一般来说,如果您有使用V8 的代码,JSC 将检查“隐式类型”/“结构”两次——每次访问检查一次,然后检查
ax
和ay
都是数字,而 TM 将生成仅检查一次a
类型的代码,并且可以(在所有条件相同的情况下)将ax
和ay< /code> 而不检查它们是否是数字。
如果您目前关注的是纯粹的执行速度,那么会出现一些好坏参半的情况,因为每个引擎在某些任务上似乎都比其他引擎做得更好——TraceMonkey 在许多纯数学测试中获胜,V8 在高度动态的情况下获胜,JSC 在有条件的情况下获胜。混合物。 当然,虽然今天是这样,但明天可能就不同了,因为我们都在努力提高绩效。
我提到的另一个问题是 DOM<->JS 绑定成本——这实际上可以在 Web 性能中发挥非常重要的作用,最好的例子是 Dromaeo 基准测试中的 Safari 3.1/2 与 Chrome。 Chrome 基于 WebKit 的 Safari 3.1/2 分支,因此可以相当安全地假设类似的 DOM 性能(编译器差异可能会导致一定程度的差异)。 在这个基准测试中,Safari 3.1/2 实际上击败了 Chrome,尽管它的 JS 引擎显然要慢得多,这基本上是由于 JSC/WebCore(WebKit 的 dom/rendering/etc)和 V8/WebCore 之间更有效的绑定
。在 TM 的 DOM 绑定似乎不公平,因为他们还没有完成他们想做的所有工作(唉),所以他们只是依靠解释器:-(
..
Errmmm,这比预期的要长一些,所以对原来的问题是“这取决于”:D
The performance of pure DOM operations (getElementById/Tagname/Selector, nextChild, etc) are unaffected as they're already in pure C++.
How the JS engine improvements will effect performance does depend to an extent on the particular techniques used for the performance improvements, as well as the performance of the DOM->JS bridge.
An example of the former is TraceMonkey's dependence on all calls being to JS functions. Because a trace effectively inlines the path of execution any point where the JS hits code that cannot be inlined (native code, true polymorphic recursion, exception handlers) the trace is aborted and execution falls back to the interpreter. The TM developers are doing quite a lot of work to improve the amount of code that can be traced (including handling polymorphic recursion) however realistically tracing across calls to arbitrary native functions (eg. the DOM) isn't feasible. For that reason I believe they are looking at implementing more of the DOM in JS (or at least in a JS friendly manner). That said, when code is traceable TM can do an exceptionally good job as it can lower most "objects" to more efficient and/or native equivalents (eg. use machine ints instead of the JS Number implementation).
JavaScriptCore (which is where SquirrelFish Extreme lives) and V8 have a more similar approach in that they both JIT all JS code immediately and produce code that is more speculative (eg. if you are doing
a*b
they generate code that assumesa
andb
are numbers and falls back to exceptionally slow code if they aren't). This has a number of benefits over tracing, namely that you can jit all code, regardless as to whether or not it calls native code/throws exceptions, etc, which means a single DOM call won't destroy performance. The downside is that all code is speculative -- TM will inline calls to Math.floor, etc, but the best JSC/V8 can do would be equivalent toa=Math.floor(0.5)
->a=(Math.floor == realFloor) ? inline : Math.floor(0.5)
this has costs both in performance and memory usage, it also isn't particularly feasible. The reason for this is the up front compilation, whereas TM only JITs code after it's run (and so knows exactly what function was called) JSC and V8 have no real basis to make such an assumption and basically have to guess (and currently neither attempts this). The one thing that V8 and JSC do to try and compensate for this problem is to track what they've seen in the past and incorporate that into the path of execution, both use a combination of techniques to do this caching, in especially hot cases they rewrite small portions of the instruction stream, and in other cases they keep out of band caches. Broadly speaking if you have code that goesV8 and JSC will check the 'implicit type'/'Structure' twice -- once for each access, and then check that
a.x
anda.y
are both numbers, whereas TM will generate code that checks the type ofa
only once, and can (all things being equal) just multiplya.x
anda.y
without checking that they're numbers.If you're looking at pure execution speed currently there's something of a mixed bag as each engine does appear to do better at certain tasks than others -- TraceMonkey wins in many pure maths tests, V8 wins in heavily dynamic cases, JSC wins if there's a mix. Of course while that's true today it may not be tomorrow as we're all working hard to improve performance.
The other issue i mentioned was the DOM<->JS binding cost -- this can actually play a very significant part in web performance, the best example of this is Safari 3.1/2 vs Chrome at the Dromaeo benchmark. Chrome is based off of the Safari 3.1/2 branch of WebKit so it's reasonably safe to assume similar DOM performance (compiler difference could cause some degree of variance). In this benchmark Safari 3.1/2 actually beats Chrome despite having a JS engine that is clearly much much slower, this is basically due to more efficient bindings between JSC/WebCore (the dom/rendering/etc of WebKit) and V8/WebCore
Currently looking at TM's DOM bindings seems unfair as they haven't completed all the work they want to do (alas) so they just fall back on the interpreter :-(
..
Errmmm, that went on somewhat longer than intended, so short answer to the original question is "it depends" :D
它们是纯 JavaScript。 除非在 JS 中实现特定的 DOM 方法调用,否则它们的效果很小(并不是说还没有在减少此类调用的开销方面开展工作) )。
DOM 优化是一个完整的“另一个
松鼠猴子蜘蛛鱼......布局甚至渲染引擎开始发挥作用,每个浏览器有自己的实施和优化策略。They're pure JavaScript. Unless a particular DOM method call is implemented in JS, they'll have little effect (not to say there hasn't been work done on reducing the overhead of such calls however).
DOM optimization is a whole 'nother kettle of
squirrelsmonkeysspidersfish... The layout and even rendering engines come into play, and each browser has their own implementation and optimization strategy.