Faster web

If Virtual DOM is slow by design, and DOM API is tedious to use, how do we get the faster web?

Hajime Yamasaki Vukelic
codeburst

--

It seems like yesterday when Vue surpassed React in GitHub star wars. Of course, stars don’t mean much. There are still plenty more React jobs compared to Vue. And let’s not forget Angular. While the three giants are battling it out, I cannot help but notice they have one thing in common which makes the choice mostly about taste, and arguments surrounding the choice quite absurd.

So you want fast or not?

The thing the three of the big boys have in common is the speed… or lack thereof. Developers are battling it over whether one of the big three are faster than the other, not even realizing the absurdity of what they are doing. If you care about speed, why are you even using any of the three? They are all slow. Period. You may not believe it (and you will by the end of this article), but all three are orders of magnitude slower than what’s possible today.

Those of you who have read my earlier articles like Taming huge collections of DOM nodes, and why Virtual DOM is slower know that this is inevitable. And I said at least once that coding in vanilla JS is the way to go if you absolutely need speed. But that is not at all what I’m going to talk about here. What if I were to tell you that this new thing is even faster than vanilla?

Still, performance matters…

Back to performance, though. There are many reasons performance is important. Developers are rightly getting worked up over it. We are writing user-facing applications, and why would anyone like them to be slow to respond? It should be fast. And not just on powerful developer machine, but on anything down to a cheap mobile phone. We all know this. Computers are getting powerful, so they should be able to do a lot more. This has still not become a reality simply because we are using tools that optimize for developer UX and hand holding beginners rather than offer a substantial solution to current performance problems.

Another dimension to performance is the exact same thing developers claim to gain by sacrificing performance — developer experience. The reason this eludes most developers (myself included), is that DX is improved by performance only when performance is extreme. Making any of the big three 20% faster will not get you there. Not by a long shot. I’m talking about 2000%~5000% faster and more.

What happens when you have something that is 20~50x faster than your choice of modern main-stream front end framework is you no longer need to worry about state management. You don’t need shouldComponentUpdate() or code that prevents state updates when it’s not really necessary. What you do is you simply re-render the entire application and that’s it. Your state store can then become just a simple object and your data manipulation functions can be… well, normal functions. It takes so much of the complexity we have in our apps out of the equation. I bet you can already see how much better developer experience would be if you did not have to use Vuex, Redux, or any kind of complicated specialized state store. You create a plain object, and stick some data in it, and you are done. Simple.

The new realm

So what’s this thing that’s over 20x faster than React/Vue/Angular?

The name of the new era in front end development is Imba. OK, OK, that was way too dramatic. You’re now probably thinking “Yeah, right, everyone would be using it if it were that good.”

Well, first of all, it is that good. Here’s the proverbial proof:

Screenshot of a DOM reconcile benchmark created by Imba’s own author (Imba on the left, React middle, Vue on the right)

The code for the benchmark is on GitHub if you are curious. There is also a more technical article by the author of the Imba language, that discusses the benchmark.

What the above shows is a result of running a bunch of manipulations of a common state store and then forcing the respective frameworks to re-render the view with the modified data. The red numbers at the top show you how many times the store was reshuffled and view updated. The numbers at the bottom show you how many operations per second the framework is capable of achieving during the benchmark.

Depending on the machine you are using, you can literally see the difference. It’s a non-superficial improvement in performance that blows anything else out of the water.

With Imba, the benefits of extreme performance to DX are real, too. The application doesn’t selectively re-render parts of it. It re-renders everything. There is no built-in state management… because it does not need it. It also has a “view as a function of state” philosophy with render functions that simply render the current state of the application without separate branches for creation and updates (which is not something you can do with vanilla, btw.). It’s so efficient, in fact, that you can either make it automatically re-render on any DOM event (default) or even on animation frame (great for games and similar soft-real-time use cases).

Here’s a small and complete Imba app:

var store = {
title: ""
items: [
{title: "git clone hello-world-imba", done: true}
{title: "npm install", done: false}
{title: "npm run dev", done: false}
{title: "play around", done: false}
]
}
tag Item
prop toggleDone
def toggleDone
data:done = !data:done
def render
<self>
<li .done=data:done>
<span :tap.toggleDone> data:title
tag App
def addItem
data:items.push(title: data:title)
data:title = ""
def render
<self.vbox>
<header>
<input[data:title] :keyup.enter.addItem>
<button :tap.addItem> 'Add item'
<ul> for item in data:items
<Item[item]>
Imba.mount <App[store]>

Apart from the Ruby-inspired syntax with a Pythonic/CoffeeScript-ish twist, you will see that it pretty much looks like any other modern framework. It has components, render methods, and JSX-like syntax for tags. It is apparent that DX is not being sacrificed here. At least not for the author. You will also see that the state “store” is just a plain JavaScript object. And that takes care of an entire class of complexities arising from having complicated state management. Not that you can’t use state management, mind you — you just don’t have to.

How does it do that, though? Well, Imba is a compile-to-JavaScript language. And it’s in the compiler that the real magic happens. The compiler takes your code and splits it into create and update branches. You code as if it’s all just one render() function. It is probably one of the best uses of compile-to-JavaScript to date (at least for the front end)— it does something that can only be done by compiling. If you are curious about the details, you can read more about this in the documentation.

What about Vanilla!

In theory, you could achieve the same thing Imba does by hand-coding DOM API calls. Again, in theory. Unless you are really good, or don’t mind ugly code, I wouldn’t count on the same level of performance.

I’m not an expert by no means, but that still did not prevent me from attempting to write a Vanilla JS version of the benchmark. Sadly I couldn’t make it less than 3x slower than Imba.

Screenshot of the DOM reconcile benchmark with Vanilla JS included on the far right.

I probably could do better if I wrote a much uglier version of the code. At least that’s what I’d like to think. That would simply make Imba look even better because it achieves this performance without sacrificing developer experience or introducing ugliness into the code.

So why no 100k stars on GitHub?

Don’t ask me, I’m not a star expert.

Imba is not widely used, though, that’s for sure. Hey, not even Vue is widely used even though it has over 100k stars on GitHub.

I guess part of it is that it’s a new language. It looks like Ruby, feels like CoffeeScript (in the sense that it’s similar enough to JavaScript that you may try to do something that doesn’t work), and it’s not JavaScript. Editor support (exists but buggy), tooling support (no gettext for you!), and all the familiar issues surrounding new languages are there, too. Good luck convincing JetBrains to release an Imba plugin any time soon.

Another part is the documentation, which is currently still a bit sketchy, and I keep running into undocumented syntax even in official screencasts. After getting a bit frustrated with the language, I decided to dig into the compiler code itself to see what it does. Good luck to me.

All of that is besides the point, though. Those issues can be fixed and probably will be in near future. Whether you end up using Imba or not is not important here.

What’s important is that Imba has broken cleanly though the current generation frameworks’ flight envelope, and entered a territory where development is simplified because of the performance. It shows that performance does matter, not just for the end user, but also for us as developers. It’s a hint at what’s possible and what we should be looking for in the next generation frameworks. It turns out it is not FP, nor static type checking, but extreme performance.

--

--

Helping build an inclusive and accessible web. Web developer and writer. Sometimes annoying, but mostly just looking to share knowledge.