6 ms·
I wonder if they had chosen to compile to the standard DOM implementation if there would still be a huge performance gain over the current execution speed? DOM
by austincheney 7y ago
I wonder if they had chosen to compile to the standard DOM implementation if there would still be a huge performance gain over the current execution speed?
DOM operations, in JavaScript, on Firefox already occur at near assembly speed at billions of operations per second. Comparatively abstractions over the native DOM implementation, in JavaScript, are many orders of magnitude slower. While I understand this is a C++ application compiled to WASM it still begs the question if this application is potentially sacrificing performance for a more popular implementation such as the nonstandard JSX vDOM.
- bgirard 7y ago> DOM operations, in JavaScript, on Firefox already occur at near assembly speed at billions of operations per second. Citation needed. At 1 retired instruction per cycle that's 1 instruction per DOM operation to hit 2G operations / sec on a 2 Ghz clock.
- ithkuil 7y agowhile clearly, effective instructions per cycle depend on the workload. That said, https://en.wikipedia.org/wiki/Instructions_per_second https://en.wikipedia.org/wiki/Instructions_per_second mentions AMD Ryzen 7 1800X reaching "304,510 MIPS at 3.6 GHz", which would give you a budget of 152 instructions in order to achieve 2 billions of operations per second (I assumed you took the plural to mean "integer plural", i.e. at least 2 billions :-) ) Now, I agree that it's a bit of a stretch to assume DOM operations won't hit some memory fetch bottleneck or something else, but parent's estimate is not miles off.
- bgirard 7y agoDOM operations in this context is single threaded and definitely not deeply pipelined cached friendly code. I benchmark web code using cycles and instructions and I'm finding in practice that we're averaging in the order of 0.5-2 IPC in chrome for the web render process's main thread when running real world code. 152 IPC would be amazing!
- austincheney 7y agoI found that Chrome runs these instructions about 20x slower.
- tannhaeuser 7y agoMy understanding is that's CSS reflows what makes DOM operations expensive (plus maybe re-building redundant/cached DOM structures such as document.links and informing event listeners), rather than trivial tree insertions. You could also batch multiple DOM updates by just constructing an off-screen DOM element hierarchy and then finally attach it to the live DOM, replacing anything below a given node in a single atomic operation. AFAICS, DOM diffing really only adds value if you have DOM updates from many sources/components to merge for very complex React-like apps. Happy to be corrected by actual performance figures/experts.
- The_rationalist 7y agoMy understanding is that's CSS reflows what makes DOM operations expensive This is why CSS contain property is such a big performance revolution. There is also if I remember well, a special kind of Dom that is only for logic, therefore being unaffected to reflows. I don't remember how it's called.
- lioeters 7y agoYou're probably thinking of CSS position absolute or fixed, which are "outside the flow" and can be used (i.e., for animation) to minimize reflow.
- lootsauce 7y agoI believe you are speaking of a fragment. https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment https://developer.mozilla.org/en-US/docs/Web/API/DocumentFra...
- The_rationalist 7y agoExactly
- FpUser 7y agoCan you please tell what exact operations on DOM are capable of being executed at "billions per second" rate? Got any link to read about a matter?
- banachtarski 7y ago> DOM operations, in JavaScript, on Firefox already occur at near assembly speed at billions of operations per second Call me skeptical
- adev_ 7y ago> Call me skeptical Yep. I call that FCA/FMA numbers [1]. Only a simple memory allocation is an order of magnitude slower. And I am not even speaking about the cost of boundary crossing between the JS engine and the C++ DOM/render API. [1]: https://www.youtube.com/watch?v=Y21xzVH8NGY https://www.youtube.com/watch?v=Y21xzVH8NGY
- austincheney 7y agoYou can see for yourself if you go to https://jsbench.github.io/ https://jsbench.github.io/ Test document.getElementById("canvas"); against document.querySelector("#canvas"); On my really old desktop computer I am running about 800 million operations per second in Firefox 74 on Windows 10. See what numbers you can get up to with modern hardware or a different operating system.
- blattimwind 7y agoI'm getting about 2.5 bn op/s, which suggests this is rather down to the JIT's ability to elide microbenchmarking code. Edit: Worth pointing out that the linked page runs on an eight year old version of the "benchmarkjs" package, which is described as a robust benchmarking package, but while the linked blog posts discusses some issues with JS benchmarking, how to trick the JIT into actually still running your NOPs is not discussed.
- austincheney 7y agoYou make a couple of assumptions and I am not sure they are correct. 1. JIT's ability to elide microbenchmarking code This can be easily debunked using a combination of DOM instructions and taking note of how dramatically the ops/s count drops and then comparing that difference in ops/s against the same difference from another browser like Chrome. If both browsers report wildly different base numbers but similar ratios then there is no cheating for micro-benchmarking numbers. 2. Worth pointing out that the linked page runs on an eight year old version of the "benchmarkjs" package I found a different site that reports similar numbers so either they are using the same old code or the numbers valid without regard for the old code. https://jsbench.me/ https://jsbench.me/
- imtringued 7y agoIt's all about batching. Sometimes doing a tiny change can cause the entire page to re-render. If you render your templates directly to the DOM you might start a rerendering chain that needlessly wastes performance. The other benefit is that the vDOM reduces the number of changes to a minimum. That's good but it's the rendering that kills performance. Changing 1000 or 10 DOM nodes doesn't matter that much.
- infogulch 7y agoWe don't need vDOM, we need a batching/transaction interface to the normal DOM.
- tannhaeuser 7y agoDOM already has a "batching" interface: construct an arbitrary complex new node off-screen, then use eg. replaceChild() on the live DOM (possibly using importNode()/adoptNode()) to attach it as the last step of your event handler.
- lhorie 7y agoThat has two problems: 1) this technique doesn't work if you need to keep part of the DOM (e.g. a focused input or a running video) 2) this technique is O(n) in IE
- jlokier 7y agoThis technique should be O(n) in every browser (where n is the size of the inserted tree), unless large parts of the tree are hidden with display:none. After replaceChild(), the inserted tree must be analysed in context for CSS, layout and rendering. That will take O(n) unless parts can be skipped. Do you mean that IE does a separate CSS or layout calculation for each node as they are inserted one by one?
- austincheney 7y ago> Sometimes doing a tiny change can cause the entire page to re-render. What kind of change? If you are talking about repainting the visual CSS rendering to the viewport that isn't the DOM. That is your hardware. This is why modern browsers use GPU acceleration. Changes to the DOM are changes to the DOM tree and the markup represented by that tree. These changes can have second order performance implications if the change to the tree results in adding/removing many nodes of it results in execution of events, which is outside the DOM, that result in the execution of additional DOM instructions. > If you render your templates directly to the DOM you might start a rerendering chain that needlessly wastes performance. I have never encountered this. Could you provide an example?
- namelosw 7y agoWait... Wasn't one of React virtual DOM's original motivation "DOM operations are so expensive so we need to use virtual DOM to reduce those operations"?
- lhorie 7y agoDisclaimer: virtual dom library author here One does not simply "compile to the standard DOM" to get performance gains. A virtual dom is a binding abstraction, meaning it provides a "declarative" interface and then figures out at runtime what values have changed. This costs allocating memory for a virtual dom representation of the view. If you want to compile away the virtual DOM, then the compiler has to be aware of how data changes propagate through your model. Svelte, for example does this by tracking assignments in a flat component file, but since it doesn't introspect very deeply, if you put something like redux on top of it (or even if you simply assign a deep data structure), you're going to get a relatively inefficient redraw load (this is essentially the dirty-checking problem from angular 1). Yes, a compiler could in theory be smart about it, but it then needs to be deeply aware of the runtime semantics of the language to mount the reactive model on top of it, and this is far more complex than what you can do w/ just babel-style parsing. I'm not aware of any js compiler today that is able do the level of language introspection required to be the elusive "sufficiently smart compiler"[1]. [1] https://wiki.c2.com/?SufficientlySmartCompiler https://wiki.c2.com/?SufficientlySmartCompiler
- austincheney 7y ago> If you want to compile away the virtual DOM, then the compiler has to be aware of how data changes propagate through your model That makes the assumption that a virtual DOM is needed for efficiency because the model exposed by a framework instance would be doing extra work otherwise. That is a red herring for two reasons: 1. You don't need any framework, whether MVC or otherwise, to have a fully expressive application written in JavaScript. If there is no framework and no model there is nothing superficial to be aware of or propagate through. Perhaps the vDOM provides performance improvements compared with other framework techniques. The compiler doesn't need to be smart when unnecessarily complex considerations are taken off the table. 2. There are only two classes of APIs exposed by the browser to JavaScript: The Web APIs and the DOM. Regardless of how clever or organized any framework is it still ultimately interacts with the page using the same basic set of instructions as everything else. For example a JavaScript framework isn't exposing new access points to hardware, memory, or markup artifacts that aren't already available as web standards. The performance benefit of bypassing a virtual DOM is simply due to executing fewer instructions, which means not executing a giant framework in addition to bypassing its virtual DOM. As an analogy I don't need to blow up a dam and change the course of a river to put out a camp fire, but if I were going to put out a campfire by diverting a river I now have many additional performance factors to consider.