Million: less than 1kb virtual DOM that is fast
millionjs.org
millionjs.org
It was a decent idea to optimize for these browsers and FB's nature of featuring hundreds of comments etc. that could be updated somewhere outside your view port and cascade nevertheless into repaints and reflows. Remember the FB feed?
I also worked on virtual DOM optimizations back then for these IEs, but have long since abandoned optimizations. I take it with Svelte: https://svelte.dev/blog/virtual-dom-is-pure-overhead
Also Google sheets results show overall, that DOM is faster than any virtual DOM, so why produce overhead? https://millionjs.org/benchmarks
Virtual DOMs are a thing that people long time ago forgot why and for what technology it was invented. Then came Google Chrome and their optimizations.
For benchmarks, I think this is still the best around: https://krausest.github.io/js-framework-benchmark/current.ht...
It is a tool to make functional reactive programming style _almost_ as performant as direct dom manipulation.
The comparison that's relevant here is, how long does it take to repaint the view if I recompute the view as a function of my state every time my state changes?
Compared to rebuilding the dom tree on every change, using a vdoms and diffing offer a huge speedup.
Using jquery/vanilla js to update thr dom in an adhoc fashion in response to user input (when the user clicks "next", then add a class to this dom element, remove this other element from this other random place...) has always had faster runtime, it's just more likely to be coded wrong.
FRP is an abstraction that makes writing and reasoning about correct UIs easier. Vdom is a technique that makes this abstraction practical.
Performance was definitely it's primary purpose.
Remember Flux? THAT was the architecture that introduced FRP to the masses (based on the Elm architecture). The VDom was invented because large dom trees were too slow when you got to thousands (maybe tens of thousands, I forget) of nodes. Which is hilarious if you think about it .. somehow the C++ DOM update loop was slower than someone clever doing it in single threaded JS.
> Using jquery/vanilla js to update thr dom in an adhoc fashion in response to user input [...] has always had faster runtime
This is very incorrect.
> it's just more likely to be coded wrong.
While not outright wrong, I find this somewhat debatable. React is pretty complicated these days and it's quite easy to get tangled up if you're not conscious of what you're doing. FRP isn't a silver bullet.
Reading an element property, adding/updating a nearby element, and then reading another element's property took FOREVER. Enter the virtual DOM. Since it did not engage the actual rendering engine, the reads and writes did not trigger reflow. At the end of the code segment, the actual DOM actions became effectively write-only. Even though the virtual DOM was slower per access than the actual DOM, the end result was a MASSIVE speed up.
This message brought to you by someone who honed their skills for a decade to batch their reads and writes in vanilla JS only to have those new-fangled frameworks take care of it (and data binding) for you. Jerks.
So what you're you saying is that at the granulatity of a single tick a VDom increases performance significantly due to not having to wait for the browser to recompute the dom after writes.. correct? It effectively batches writes, and thus the need for the renderer to get involved, which increases read throughput because reads block till after the DOM was recomputed. And the DOM is recomputed on every write thats followed by a read.
Makes a lot of sense, thanks for the input; I was completely unaware of this case. Any idea if this is still the case? Do you happen to remember what browsers and/or hardware that saw dramatic improvements (CPU gen would be great)? I'm thinking of doing some deeper perf investigation/spelunking on the subject to satisfy my curiosity. I remember things one way but a lot of people seem to think the opposite..
Part of the browser API is querying all current CSS properties of an element, e.g., getComputedStyle(…). The only way to get this is by having the layout engine do all its work, so properties like height and width can return accurate info.
Most virtual DOM implementations just skip parts of the API like this. At best, they make an educated guess without hitting the actual renderer. Or they just allow a pass through to getComputedStyle(…) and warn you away from using it due to performance concerns.
It's all smoke and mirrors topped above a bed of lies.
This is untrue as written after a decade of fanboys making this exact claim. I think your point that it’s an optimization for a particular style is correct but starting with this encourages knowledgeable readers to skip your comment.
you don't need vdom to make this fast.
you compute your state in whatever data structure you like and then requestAnimationFrame updates the DOM if and where it is needed.
VDom is much like double buffering in video games, it was useful when video memory was scarce and access times were slow, but it has lost much of the appeal on modern HW.
Double buffering still has a huge appeal on modern hardware - tearing. At 144Hz/fps, a single frame is 7ms, and at 30, a single frame is 33.3333ms - the margin for error is significantly lower. At high refresh rates, I'd rather an extra frames latency to tearing.
or to make it more clear: VDom is unnecessary because the browser engines have adopted optimizations that made it obsolete, just like many rendering techniques are not used anymore because the HW implements them in a more efficient manner.
For fast rendering speed in browsers, support for HW acceleration has done more than anything else combined.
Double buffering is still widely used by native code (e.g. inside the browser, inside video games, inside native toolkits). Ergo, "VDOM is obsolete the way that double buffering is" makes no sense.
OTOH, "double buffering from code running in the browser is now obsolete" may make perfect sense, following changes in how the browser itself interacts with the HW.
AFAIK (not worked on a game in years) double buffering, when I first heard about it, was used to overcome a limitation of the HW, we had graphic/video cards (when I started programming EGA was the standard), GPU did not exist, the amount of memory was limited, data transfers were slow, double buffering meant having two in memory buffers, the active one and the next one, being built in the background, that were alternatively sent to the graphic card.
Then VGA added page flipping, you could write two buffers in the graphic card memory and instruct the card to swap the active page by flipping a bit in a register during vsync and then write the next frame in the inactive page.
From then on things have improved exponentially, to the point that now GPUs can buffer multiple high res frames, so while frame N is being displayed, the CPU can elaborate frame N+1 or N+2 or even N+3 on some GPU. The framework configures the GPU to automatically swap frames (usually in a FIFO queue) on vsync.
I think in Vulkan this workflow is called swapchain.
HW implemented what was possible only in SW, double buffering is still in use of course, habits die hard, but the issue it solved is not remotely as bad as it used to be.
VDom followed the same path, it was invented to overcome a browser's limitation: DOM access was painfully slow, especially on legacy browsers like IE.
Now they are fast enough that VDom, even though technically still largely in use, is not an hard requirement to make fast DOM updates like it was 10 years ago.
It stayed there in many frameworks, IMO, because you'll never know what HW/SW combination your users are running, backward compatibility, "if it ain't broke, don't fix it"
Not sure why you'd call this an "exponential improvement". Using more than 2 buffers increases display latency, which for most (not all) purposes is undesirable. Double buffering (that is, just using an active/inactive buffer) is almost always the best thing to do, regardless of where the memory is located or who is responsible for the buffer swap.
It's funny to read this when Google Chrome has constant tearing on Windows.
if you rendered your web app in an animationFrame in the allotted time (60hz usually, 1/60 of a second) you won't notice any flickering or tearing even without double buffering.
modern HW (screens and GPU) use complete frames, so flickering and tearing are not an issue if the writes are vsynced.
{tag, [attributes], [children]}
but your application state could be whatever you want, it doesn't need to be in the same shape of the DOMthe only problem VDom really helped with was DOM diffing, but browsers are fast enough nowadays that it's not a big issue anymore.
No one is saying update DOM elements manually. They're saying there's better strategies for view libs than VDOM.
- creating actual DOM elements during render and diffing that with the DOM, or
- using the existing DOM as the thing being diffed against your new vdom (slow because calling into the browser many times may be slow and you need to check eg there aren’t attributes to be removed from your elements)
Perhaps it’s also necessary to mention that the main point of vdom was to allow react to offer the API it does performantly but maybe with compiler-based solutions like svelte that isn’t necessary. Lots of people still use react, however.
If you are building any abstraction on top of the DOM to handle that, then you have effectively built a virtual DOM.
Or are you suggesting that setting innerHTML and allowing the browser to re-construct the DOM is now faster? I can assure you that is not the case!
TBH, looking at the benchmark code for partial updates, im not sure I have much faith in the benchmarks overall, but certainly eye-opening regarding the innerHTML performance.
Even if we set that aside, the differences between something like Svelte and React are still likely to be far less than the differences you'll gain from changing to a more efficient algorithm.
I'd be curious to know whether this holds true for other browsers out there.
Just saying there are probably situations where these might still offer a genuine functional benefit, simply by virtue of offering abstraction.
There are a bunch of replies here focusing on how nice to use virtual DOMs can be, would gently encourage those folk find another industry to ruin.
This is where I think React is getting things right. The work that's been done on React 18 attempts to work out what events are most important, and schedules the DOM changes from those interactions ahead of changes from other events. It batches the changes over a number of frames if there's a lot of them. This means that a UI made with React will probably be slower than other frameworks, but it'll feel faster. The changes that result from your interaction happen first. That's what users want.
Ultimately every framework has an upper bound for performance, and if you're not hitting it then the framework speed doesn't really matter. If you are hitting it though, then React's approach is better because it optimizes for the bit the user cares about. The fact that Solid, Svelte, etc are technically better, and therefore faster, means there's lots of additional headroom for using that speed, but once you actually cross the threshold of what they can do things will start to feel slow very quickly.
And this is where that matters - many web developers just aren't great at writing code, so if the framework can scale a 'fix' for what they build that will result in a better user experience than simply giving the developer more speed. A faster VDOM is a good thing, and no VDOM at all is an even better thing, but ultimately you could make the fastest framework ever and some developers will still write things in ways that feel slow.
The right approach for fixing UI on the web is to make a framework that focuses on doing the important DOM changes first, even if it does them a bit slower than the other approaches.
I'm curious if anyone is working on and had success with using differentiable (in the math sense) expressions of dom construction from state/events in order to allow the runtime to easily calculate diffs given state changes/events.
But... I actually read your comment too quickly, you were not making that point :-)
On the server side, a pile of microservices that are designed around team responsibility, with requests that require requests that require requests to respond to common API calls. The desire to write the backend in JS causes a very low perf ceiling on a single instance which means a medium sized web app needs a dns lookup, load balancer hit plus reverse proxy in place for (m)any of the API calls, even if they're internal/trusted.
These apps are tested and benchmarked on the highest performance professional computing devices on local networks with gigabit connections, and then deployed to 5-10 year old computers running on 10Mb connections shared between 4 people. The servers are deployed to a large number of low cost cloud instances running on a virtualization layer inside a virtualization layer on "enterprise grade" (read: slow) hardware with real world disk and network speeds that are orders of magnitude slower than what is used for testing.
Pick any/all of the above!
If those same developers used a 10 years old PC and a semicrappy 4g netwrk I bet the overall quality of the products that comes out would be ten times better.
PC gaming has always been performance-driven, and performance variability/customization has been part of the end-user experience since the first 3dfx cards and graphics settings screen (and before that too).
Web... until recently it wasn't really a consideration for users or devs, because everything was just basic HTML and CSS and it was big images or videos that was the problem. Then, within like a decade, suddenly all these JS-heavy frameworks took over and everyone jumped on board, and connectivity has struggled to keep pace. Web developers (the humans) too struggled to keep up, with everyone having to relearn the framework du jour every year or two, with all the optimization techniques of the previous generations thrown out or made irrelevant by new frameworks & browser optimizations. I've never met a web dev who seriously even considered performance beyond some superficial metrics -- I've never seen anyone use the profiler in Chrome or their IDE at all -- much less knew what to do about it even if they did. It's just not really a thing, at least in the small to med business space. Maybe if you're working in big tech or framework development that's different, but otherwise, performance is near the bottom of considerations for web dev. Which is why we have articles like this every once in a while... it's actually newsworthy when people go "hey, JS is slow again, here's technique #33 million to speed it up", to which most of us will go "oh, that's nice, but I can't replace my whole stack just for one speedup, and besides, this new thing is going to be obsolete by September anyway."
Or some dev writes an onScroll or onHover function with zero debouncing.
There's a lot of problems in web apps that make them feel slow, but they mostly distill down to developers following some bad practises that are easily avoidable. Web apps that are slow because they're maxing out what the framework is capable of are very, very rare. Making a faster framework won't fix the ones that are just coded badly. Making a more intelligent framework might.
I've not seen this too often frankly - that tends to result in a "hung" state for a UI where the app appears to not respond. The most frequent issue I've seen is long transition animations (500+ms) to mask network calls, even when they're not necessary.
> Making a faster framework won't fix the ones that are just coded badly. Making a more intelligent framework might.
This x1000
I think of "pure JS" as something more like a standalone node function that takes an input and gives you some abstract data output, vs templating code whose main purpose is to define elements in the DOM.
That you can intersperse with JS with DOM-like props in a JSX component (styles, states, handlers, whatever) doesn't mean that JSX isn't a templating language. It's just one that also accepts inline JS. Hell, you can do that with PHP and heredocs/template literals.
Aren't all templating languages "syntactic sugar"? Isn't that their point?
(language) could be JavaScript as far back as 2000 as far as I know (ASP) — probably earlier and I just hadn’t heard of it.
Dont forget that Google's crawler is literally Chromium these days. https://searchengineland.com/google-will-ensure-googlebot-ru...
Anywhere an app is serving public content using React it should be using some sort of server side generation with hydration and progressive enhancement, which entirely negates the need for a fast VDOM for SEO reasons.
I am currently in early stages of writing a lightweight reactive framework more of the likes of Alpine and there are some things in this source that can prove fruitful. The rendering process is one of the most interesting things here imo.
m('div', {id: 'box'}, ['hello'])
[1]: https://millionjs.org/docs/api/basics/mThat's an awesome term and I'm going to steal it.
And I agree, it's a great term :)
I've just never seen it in abbreviated form, and that's kind of shocking to me because it's so obvious.
it's pretty hard to break into the sub-1.15 factor club without code smell. in fact, mikado is suspiciously fast for not having any caveats listed; something about its impl might be unusually bench-specific.
https://krausest.github.io/js-framework-benchmark/current.ht...
"do your own benchmarks" is too handwavy a dismissal, imo. btw, my own framework is in this list, and has been for a long time, to keep me honest.
My intention wasn't to dismiss your point at all btw. My intention was if there wasn't any 3rd party benchmark for a library (like js-framework-benchmark), you shouldn't take claims at face value unless you've done due diligence. It's great to hear that you're keeping yourself accountable, hopefully Million will also sometime soon :)
I'm open to different ways to market Million if there is a specific tagline you have in mind
(a) This is actually a React replacement, like Preact, not just a virtual dom.
(b) The homepage marketing is misleading! The project lost a bit of integrity for me at that point, and I started trusting it less.
If the homepage marketing is declaring it to be a virtual dom, then I want to see how to use the virtual dom API so that I can verify what it is! If it then on top of that has a React Compatibility layer, that's just awesome and makes me really excited to understand it, and I'll probably want to look at that layer so that I can see what React is beyond a virtual dom.
Anyway, do you have a pointer to how to use it as a plain old virtual dom? I happen to be in the market for one, right now!
- A VDOM (a library that lets you construct a virtual-dom, and then reconciles it with the previous one, and patches the real DOM accordingly)
- A state management/reactivity system (state hooks, effects, etc, and really also class components and their state/lifecycle)
- A framework which ties the above two together into a cohesive package for building web UIs
For me, the term "VDOM" only refers to that first point; i.e. you could combine a VDOM library with some other stuff to make a React-like framework
That could just be me, though
Now that Internet Explorer is really deprecated and DOM are fast enough in every browser, VDOM is not necessary.
And VDOM just writes to the DOM in addition to doing a lot of other throwaway work and allocations.
Reading from DOM may be slow, if you read one of the properties that would trigger layout/style calculactions.
I've written this library [1] as a clean reimplementation of a more complex beast we created for a (now dead) startup. Although the reimplementation has only seen very light use, we've used the concept extensively, and it's a joy to use. Take a look at the examples [2].
[1] https://github.com/vanviegen/aberdeen [2] https://github.com/vanviegen/aberdeen/tree/master/examples
BTW... docs point out it is written by a high school student. A very, very impressive high school student!
Completely unnecessary and just doubles the data structures and fights against the browser itself.
None of the fastest modern frameworks use it as far as I know (solid, lit, fast, svelte and stencil)
Is every user running a 2022 browser?
The worst offender I guess is Safari which has historically tied updates to a few times a year rather than much shorter cycles used in Edge, Firefox and Chrome.
Whatever delays there may be in those update cycles I’m confident that you shouldn’t need to be catering to 2012 browsers. VDOM just isn’t necessary as a performance hack and hasn’t been for many years at this point.
It is staggering to me the quantity of developers who are still made uncomfortable by the notion that you can construct a high-quality, modern web experience without pulling down a single 3rd party javascript or css dependency.
I really hope the pendulum starts to swing back the other way. It is so fast & easy now. MDN makes life a breeze. In 2022, there really isn't an excuse to not use direct DOM manipulation and bare-ass JS, other than pedantic ideological arguments such as "why is my hammer this shitty color?" and "My monster.com filter can't find 'vanilla js' skilled employees".
As noted by other posters, VDOM is essentially just overhead. It is both faster & easier to grab that element by its id and change it directly. Playing around with intermediate UI representations, 3rd party frameworks and splitting state between client & server is where 99% of your hell comes from on web development.
When you understand 100% of your javascript, setting breakpoints and tracing things in devtools has a lot more power. Hiding from the realities of the open web is only going to cause a prolonged suffering for the junior web developer. Frameworks will come and go. document.getElementById() will be here until the end of time.
bare DOM works fine up to a certain size/complexity app, and up to a certain size dev team in the single digits.
When I look at what you've written under those restrictions, the biggest problem I flag as a general software engineer is how the events get created, defined, listened to, etc. This tells me that if I was building something "large" like that, the first third-party library I'd want to integrate is something for handling those event streams in a more rigorous and robust fashion.
In my view, the size or complexity of the app has nothing to do with whether or not you should use a javascript/css framework. I believe it's more about having the experience & leadership required to pull the team together on complex, open-web technologies relative to the problem you are trying to solve.
Once a pattern has been established, its exceedingly easy for the junior developer to catch on and help out. Starting from zero is where most seem to struggle with the web. I've never had someone come to me and complain about the difficulty around adding a new field to an existing web form.
We were using a blend of Angular JS, Riot JS and Blazor over a period of ~8 years before we had the experience & confidence to dive into a 100% vanilla JS product. I can't fault anyone for reaching for something off the shelf to get started. But make no mistake - If you have the team, opportunity & experience to pull it off, vanilla JS products are the most enjoyable to develop & maintain. It is incredibly empowering relative to managing something like an Angular 1.x/2.x codebase, or even a modern Blazor server-side app.
I will also say this - The state of the open web standards is amazing in 2022, so you might be able to shortcut the training wheels a whole lot faster. Imagine if you had CSS grid from the very beginning. There are a lot of self-professed web developers who don't even know about this today because of the layers of ridiculous abstractions they are buried underneath.
whatever method you choose to solve this in a uniform, non ad-hoc manner will be your invented version of existing vdom or dom template frameworks, which save you from this madness. i use direct DOM only for writing high per libraries and when there is a need to optimize beyond what is provided by the framework.
i would like to see an open source, large web app written by a dozen+ engineers that manages without any ui layer abstraction and only uses vanillajs + discipline (jQuery+structure style!); in my experience this "utopia" is mostly a pipe dream, and rarely well justified.
I don't quite get how a framework can be described as "it's a virtual DOM that's fast". I kind of get what they mean, but is there no better term? E.g. "virtual DOM engine", "virtual DOM runtime", "virtual DOM renderer", maybe?
Some non-VDOM JSX libraries like Solid use it as a static analysis target for optimal output.
Some libraries including React use it to target non-browser render targets. Yes, React is designed to render to arbitrary views or even non-views. It’s used for rendering WebGL, native mobile apps, TV interfaces, CLIs, PDFs and probably a lot else.
As far as what’s described here, “that’s fast” is meant as “which is fast”, it’s distinguishing itself from slower VDOMs (such as React, which is exceedingly well engineered but seldom wins performance contests in recent years).
I feel old.
The imagery that jumps to mind is all T&A and once you've seen it as a mushroom-tip... it's impressive how many NSFW boundaries it manages to blend together.
The whole Javascript ecosystem needs to be burned to the ground and never spoken of ever again.
Also, that reaction is so widespread at this point, it's become boring to hear it. It's a lot more interesting figuring out how the JS ecosystem has been resilient and has not gone down the drain (unlike a lot more "critically" acclaimed languages like Lisp)
When things were not settled like they are today, Microsoft IE supported multiple languages and many people were using VBscript because it made more sense than JavaScript at the time.
Also, many new languages that transpile to JavaScript exist, because, well, for many people JS simply sucks.
I hear TypeScript is pretty big in that space.
Who knows if JS will survive WASM that promise to free programmers from having to use a single language to write web apps.
You could argue there is a lot more economic incentive to use JS to to the sheer number of jobs, but no one is being forced.
The weird thing to me is that the two main customers or consumers of front-end programming (publishers and users) never see and do not care about the underlying language or implementation! Businesses and other orgs (schools, NGOs, etc.) as well as individuals (FB users, WordPress blogs, etc.) that publish sites/apps on the web and their visitors and users never see under the hood except when something goes wrong or they deliberately click "View Source", eh?
Ergo, all this whole Javascript ecosystem is solely for the developers. It's like a giant and largely irrelevant MMORG that we play that produces mostly-working websites and apps almost as a side effect.
"Change my mind?"
Svelte is a bit too far into the world of custom syntax and special compiler magic.
Solid.js is great as it is compatible with jsx tools.
The future is definitely libraries that keep fine grained track of state and how it’s bound to the view, and then efficiently reconcile.
React is great and I’ve used it in prod for multiple years, but it does get slow at times due to too much CPU spent running vdom diff on large trees.
Million looks nice, but I'm not into developing with node at all.
Like a remake of a movie, we are long overdue.