My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Monday, April 20, 2015

The DOM Is NOT Slow, Your Abstraction Is

follow up something you shouldn't miss after reading this: Is Anyone Testing On Mobile? and more benchmark details in React + Performance blog post from @aerotwist
TL;DR this post shows that good Web performance is easy to reach with zero dependencies, totally cross browser, and using just the good old DOM. This post is *not* against the usage of any mentioned framework in particular, it's rather a voice out of the crowd that's trying to tell you frameworks are not always necessary and, if performance is really that cryptic, you don't need to adopt a new framework in order to solve that cryptic case.
Abstraction is good and it usually helps but it might have costs ... let's be free and choose when we don't need that abstraction by learning native DOM potentials: it's already an abstraction anyway, and it's also quite fast!
In 2007, the Dojo team created a benchmark called TaskSpeed in order to compare most common libaries capability and speed.
It's only in 2009, after about 2 years of boring "look mum, my lib is faster than everything else" competitions all over the web, that I've tried to put an end to the discussion showing that native DOM was better than every framework.
Unfortunately, younger developers don't have memories about those days, so this time we're virtually back in 2007 but it's rather "look mum, my DOM abstraction is faster than everything else".
There's so much FUD around this topic, that I hope I can help here clarifying, with the support of a live benchmark, one particular point: the DOM works and performs just fine, and it does a pretty goddamn good job that we should probably stop trying to replace it, replace its role, or the role of any browser engine on the Web.

The JS DBMonster Performance Comparison

Before going any further, I'd like to give you some background.
Parashuram N wrote a blogpost, explaining and open sourcing a presentation he gave about React and its Virtual DOM.
He was able to compare the same app written for react, ember, underscore/backbone, ractive and paperclip and grab results.
I'm actually happy somebody gave me a "TaskSpeed" like playground to implement a pure DOM and JS, zero-dependencies, version of this benchmark.
It's all in one page, I've put some comment, it works in every browser and it would work even in IE8 and lower if I put es5-shim and dom4 in it works even on IE8 thanks to ie8 and es5-shim via conditional comments!
Please note the code has been rushed literally in minutes, and it wasn't meant to be a team friendly code, but I've reasoned in reddit few chosen patterns.

The Benchmark Challenge

I'd like to say that the logic behind this benchmark is deadly simple: basically we have a static list of N clusters that never changes if not for some of their data and per each row.
The analysis of the data is basically absent, that is why it is possible to define static templates per row, and per top 5 queries per each row.
Since we are talking about an application that will never possibly work without JavaScript, having static html templates to consume is basically the exact equivalent of having static templates generated via JS, except we can address directly nodes so that changes will be instantly ready to be made.
Please note that I could have used a similar HTML template approach and address those nodes later on, just to make it slightly more readable. However, it was already easy and simple enough, I thought bringing in that would have been simply out of this post scope.

Am I cheating? Actually not at all: I've tried to understand what problem I had to solve and I've found a simple solution I would have used in the real-world too.
Sorting the table means simply changing the first name as well per each update, which is not a big deal.
That's a data table, the limit of rows displayed per time is static too and the amount of data a human being would be able to read and interact with is arbitrary but never that fast.
If you need unreadable tables that update at speed light then maybe you don't need a browser but a machine able to catch all those updates.

Quite Possibly Pointless

The TL;DR is that this benchmark doesn't represent any concrete real-world scenario.
If we use any framework in that list I'd say we have already decent performance, but if we consider diffed changes then of course if we do something like I've done through the DOM, which is similar to what a Virtual DOM engine would do, it will perform better than any abstraction on top brought in by your framework of choice ... If I add a listener to every cell and dispatch updates, of course it will be slower.
But then again, it would be me doing it wrong, because I need a single updated notification only after the entire table has been refreshed, not for every single cell.
Please note modern Object.observe and Custom Elements work in a similar way indeed, many changes in one update, not one update per each single change.

Compatibility and Loading Speed

What if my zero dependencies DOM version is also the lightest and the most compatible? Yes, that comes for free! The DOM has been stable for years and we should use it without fear instead of keeping avoiding it.
All JS based frameworks have target browsers. Using the native DOM, patching only few browsers, which is again in this case the IE <= 8 family that is easily fixable via unobtrusive conditional comments, grants us compatibility and no memory leaks or greedy memory operations problems.
I have this shit running locally on a Blackberry 7, palm WebOS, and Android 2 devices after simply patching this on top:
var requestAnimationFrame = requestAnimationFrame || setTimeout;
There's nothing else and it works!!! I have no idea about other frameworks, but I'd like to bet here:


Please note I've actually tested all benchmark pages on Android 2 and webOS, there's another video later on, please keep readin...

The DOM Is Just Fine

It puzzles me that developers seem to create themselves a problem and then they point the finger around to search and blame the cause: no, the DOM is not your problem, the fact you brought an over-engineered abstraction on top of a deadly simple task, like a table that needs some quick update, is the real problem you don't want to see.
It scares me that developers behind frameworks seem to be often incapable of getting some fresh air and think out of the cell they put themselves in: learning and using only that framework, ignoring everything else ... sometimes forgetting even common sense, probably shadowed by the framework approach.
Let's do ourselves a favor, let's stop being religious about any sort of framework and learn what the native world has to offer, what other frameworks have to offer too, and what's the best solution for that specific problem, which is never every problem we have!
Every framework was born to solve a very specific problem ... have you asked yourself if that is really the same problem you have and the one you need to solve?
Moreover, there will always be a faster, ad-hoc, way to do this or that and your framework cannot cover all the cases ... it's actually the opposite: the more cases it will cover, the slower it will be. So let's please stop moaning about the DOM and start doing things in a different way ... shall we?
We'll be those with most benefits, after all, so please think about it.

See Through Your Eyes

There has been some very active and passionate discussion within comments, I've finally decided to test all the links in the competition for real.
If the choice of a framework should be based on how much performance we need, then older Hardware and older devices are those struggling the most, those needing performance.
Well, it turned out that React here at least worked (not on Android 2.3, only on webOS), but it delivers the worst performance compared with underscore, paperclip, or my DOM version.
I let you judge who is the winner between these 4, and I tell you also that while ember and reactive didn't show up at all in both devices, React, as well as paperclip didn't work on my Android 2.3 smartphone.


I've also tested many other devices in the following "Is Anyone Testing On Mobile?" post, don't miss it!

Quick Recap

We've got videos, live links, comments and everything else to nail down at least some fact out of this post.
What has the DOM to offer, if we ditch a framework?
  • wider granted compatibility, it does not cost extra time or money to support more devices
  • zero overhead, if not for essential DOM normalizer polyfills. Usually dom4 is all I need, and it always worked so far.
  • decent, if not optimal, performance. If a framework based on DOM can be fast, we can be similarly fast too, if not faster in some case
  • we are using Web standards, not some in-house or ad-hoc solution, meaning we are granting ourselves free maintenance, performance boost, and updates in the future
The Web is all about non breaking, and the DOM has been there long time. It's there to stay, and learning it has been my survival kit and antidote for all these years of changes.
If you want my advice: know what the DOM is and what it does, and always be free to choose the right tool, including frameworks, and all their handy abstractions, for the right job.
Don't choose blindly after a shiny benchmark, even my DOM one can mislead if you are looking for better ease, and predefined patterns ;-)

Thanks for reading!

27 comments:

Unknown said...

Andrea,

I'm normally a big fan of your writing but I think you've missed the point here. Do abstractions have a cost? Yes, of course! That doesn't mean they're not worth it.

Firstly, the hand-rolled DOM code is really rather confusing. I can't imagine trying to maintain a significant codebase written in a similar style. Sensible abstractions allow us to write more declarative code that's much easier to read (and, by extension, collaborate on).

But secondly, the numbers don't add up. The Ractive example (disclaimer: I'm on the core team) has almost identical performance to the DOM-only version, both hovering around 21-22 FPS on my machine, and both get similar performance on mobile. We're currently making changes that increase Ractive's performance on DBMonster by about 40%. In the meantime, another library called t7 gets even better performance - around 27 FPS on this machine: http://t7js.com/dbmonster/precompiled.html

So if you use an abstraction, then not only do you get a whole load of optimisations that you might not otherwise have thought of, but your application might very well get faster over time without you having to do anything, because the library itself is getting better.

It doesn't make sense to tar all abstractions with the same brush!

Andrea Giammarchi said...

Abstractions have a cost, that's why they put PureDOM benchmark in the list at TaskSpeed time.
It was throwing shit to every abstraction but those developers knew it was a reference to actually indeed understand the cost of the abstraction ... no point missed from my side.

The hand rolled DOM code is not confusing to me, I've created manually some node following a template schema. I could have created the template via HTML and then address those nodes at creation time, it would have been pretty much the same. But it wasn't necessary 'cause the task was deadly simple, and so it was the template to recreate.

On top of that, you don't need to maintain much in there, but I think it would be easy anyway: those are simple cells.

I've tried t7 and does not give me any extra boost but yes, React has similar DOM performance, I wrote it.

I've said that if you have an abstraction that does the diff, and updates only what's needed which is exactly what I've done with pure DOM, of course you go faster ... I was rather wondering what's the point of this benchmark? Demonstrate that updating only the necessary is faster? Do you need React for that? Do you need its size, its compatibility target browsers, and its RAM cost to obtain same performance? No, that is what is this post about.

React did a good job and I understand you guys promoting it like the "Eldorado" of Web performance ... but can I promote just the native DOM as capable of same performance without any overhead at all?

I mean, kudos React .. but do developers know that DOM is pretty damn good as well?

Do developers realize that react is under your control while the DOM is a Web standard and it's there to stay? (yeah, I'm sure react is there to stay too, and will probably win on native development ... but should developers have a choice and know facts?)

All I'm seeing these days is a lot of talking on how bad is JS, how bad is the DOM ... most of the time this comes from people that don't even know the DOM or how to use it but they've been told it's bad.

I think browsers developers deserve a bit more respect, as well as standards that give us everything we need to make all these frameworks actually work.


> It doesn't make sense to tar all abstractions with the same brush!

No, but it was about the time that someone wrote an "ice bucket" counter benchmark to wake up developers that might believe there's voodoo magic behind these frameworks and the DOM is the one to blame if things don't work: these frameworks are all rendering on the DOM, sayng that the DOM is slow but a framework DOM based is fast, is fooling everyone for no reason.

Again, I'd lik eto underline that this post is not against any of the frameworks mentioned, it's against people talking shit about the DOM and its potentials, when a simple, dependencies free approach, coudl have been as shiny as this demo behind React would be.

Hope nobody got offednded, 'cause frameworks authors are not actually even this post target.

Andrea Giammarchi said...

P.S. if anyone else would like to comment in here, please don't be "that person" and use a name, thank you.

Andrea Giammarchi said...

P.S. to both Unknowns ... I've updated the post with a TL;DR on top and I've made second Unknown maybe happy ... but at the end of the day, if it wasn't me writing that PureDOM (and you should really check the benchmark and run it) those discussions would have gone forever FFS ... what can I say, actually I failed at that time since people still have these kind of competitions ^_^

Federico Rampazzo said...

The problem with the DOM is that it's not suited for applications - hence the name Document Object Model.

Unfortunately we have the business requirement of developing applications on top of it.
It's an horrible experience (especially if you're coming from greener pastures) and that's why I'll gladly take an abstraction over it.

There is a slightly different problem for mobile applications: performance difference are more noticeable on mobiles and optimizing HTML5 apps on mobile is harder there. Not impossible, you just have to know what is hw-accelerated and what's not.
Facebook namely dropped their HTML5 app because of performance problems (*aka "they weren't able to optimize it as well as a native app").
After a while Sencha showed the world a well optimized version was indeed possible (fb.html5isready.com).

But at what cost? As a developer I want to work with the right model and using the best abstraction I can in order to work more efficiently and waste less time on problems which have been _countless_ times in other contexts.

React is cool because it's trying to set a declarative standard for developing applications (which bears similarities with Qt's QML) and deploy to platform plagued by horrible dev environments: web and mobile.

Thanks for taking the time to write this benchmark, it's always good to have more data to aid future decisions.

Cheers

Unknown said...

I'm the first Unknown - I wasn't staying anonymous intentionally, Blogger just didn't recognise me after I signed in. (Blogger is terrible, news at 11...)

In case it still doesn't work, I'm @Rich_Harris, a member of the Ractive (NOT React, you misread that) core team.

> The hand rolled DOM code is not confusing to me

It never is to the person who wrote it! To everyone else, it's needlessly obtuse - full of 'clever' constructs such as abusing `this` inside the map iterators. Honestly, I don't mean to be rude, but it simply wouldn't pass a code review on any of the teams I've worked on. The right abstraction gives you and your team a shared vocabulary that avoids that problem.

> sayng that the DOM is slow but a framework DOM based is fast, is fooling everyone for no reason.

I've never heard anyone make that claim. If that's what your post is rebutting, it would be really helpful to include some links to articles or tweets where people have said that.

Your post makes it sound as though using tools and frameworks will make your app slower. That's FUD, plain and simple, even if a careful reader will run the tests for themselves and find a different conclusion. Encouraging app developers to only use vanilla DOM is like encouraging rocket scientists to only use slide rules!

Kamil Trebunia said...

“So if you use an abstraction, then […]”

1. “[…] not only do you get a whole load of optimisations that you might not otherwise have thought of […]”

Or actually never needed… Or some that may harm you… So it goes with abstractions.

2. “[…] but your application might very well get faster over time without you having to do anything, because the library itself is getting better.”

Well, browsers are also getting better. Browser vendors have teams with budgets and manpower that is few orders of magnitude bigger than React’s team.

So while it may be a fact that for a while React is faster (for some certain use cases) it may very well cease to be within few months or years.

To summarise: Abstractions are good, they server their purpose. But with tools that claim to focus on performance, that offer optimisations “for free”…
It is so easy to fall into the trap of unnecessary optimisations (and we all know how harmful premature optimisation is). I would just recommend to pick abstraction that help us with maintainability and then focus on performance where and when it actually matters. Majority of users do not need to "make DOM faster", especially not at the cost of maintainability.

Having said all that - I believe that React/Flux is doing good on both fronts - otherwise it wouldn’t be such popular.

Andrea Giammarchi said...

Federico don't forget I've worked on Mobile Web Facebook core team ;-)

React will not bring same boost there but this will change, and is changing already, thanks to the Moore's law, and the huge amount of RAM available these days on smart phones.

If it's mobile that you've worried about, I've also written the first m.here.com engine and it performed well in Android 2.2 phones without using any abstraction, and without needing a framework.

Simplicity at that time won over everything else.

That being said, React is good, I haven't said is not, but developers need to know that React cannot possibly go faster than DOM on DOM world. It can go faster on native via React native, but it won't be faster than native even there.

The main goal of this post it to open developers eyes, and on top of that, I've provided like I've done with TaskSpeed a native, pure DOM, baseline to compare if raw performance is the goal.

You should also compare compatibility, I have white pages on not so old mobile phones with other frameworks, and you should compare size: they are all 5X to 100X bigger than my solution.

Re-usability here is a myth, because templates are ad-hoc for this task, so nobody can reuse a thing unless it's the very same data provided by the very same object ... in that case, you can reuse my code too.

Do we want to compare? Let's do it properly ;-)

Andrea Giammarchi said...

Dear @Rich_Harris

> it simply wouldn't pass a code review on any of the teams I've worked on.

that's a very poor argument you have here ... that code sucks even in the native version which I've just copied. I've changed only the update and the rest leaks globals all over ... I didn't care.

Why would you focus on my style? And if you cannot read a perfectly standard/valid but rushed JS I've also explained and reasoned, what can I do for you here? Do you need some extra explanation?

If you've never seen a pattern, does that mean the pattern is wrong?
Or maybe you are just changing topic?


> Encouraging app developers to only use vanilla DOM is like encouraging rocket scientists to only use slide rules!

Encouraging app developers there's only one way, and that's the framework one is making them blind.

You might not need frameworks, this is not FUD while any different claim would be.

This post is fair for developers, I'm sorry it hurst the React core team. It shouldn't, IMO, it's an alternative.

Why only the core team should have fun with the native DOM ... I don't get it, I've fun with it too. Deal with it?

Unknown said...

Andrea,

Once again, I (Rich) am NOT a React core team member, or even a contributor. I don't know where you got that idea! The React version is slower than yours, but Ractive, Paperclip and t7 are all the same or faster (on Chrome, on my machine - no benchmark is truly objective, of course).

> I've changed only the update

That's the part I was referring to - the bit that's different from all the other examples. I agree, the data.js stuff is pretty crazy, I think it's just meant to simulate a firehose from a database, and isn't meant to resemble any code you'd find in a real app.

> Thank You ... I fucking hate when discussions end up like this.

Me too. But you have to realise that you're a very influential and respected blogger, and a lot of people read your stuff. So when you say unnecessarily combative stuff like 'it scares me that developers behind frameworks seem to be often incapable of getting some fresh air and think out of the cell they put themselves in', you set the tone for the discussion that follows. Like I said though, in general I'm a big fan of your writing - I've learned a lot by reading your blog.

Andrea Giammarchi said...

*Reactive

I've mis-read indeed ... apologies for that, also removed last rushed comment.

BTW, this is the catch:

I've never said in the entire post, before or after editing, that my benchmark is faster than anything else.

All I've said is that you can go fast just with the DOM doing operations in a different way.

Do you need a framework to go fast?
NO-BLOODY-NO, PERIOD!

Matt Perry said...

React != Ractive, just to reiterate that point.

Most of these frameworks are far easier to read and write than native. You might disagree, but then I disagree. Where does that leave us? As you said in your deleted post, why do you need this much performance? Most of these frameworks are fine.

Andrea Giammarchi said...

You guys should put a $ in front on one of the name :P

Apologies for the rushed comment and for the misconception, I just felt attacked for no reason.

I'm here to inform, not to blame or hurt directly anyone. If I'm accused, that's my "Reaction".

My benchmark performs just fine, it will rarely be outperformed that much, and as soon as the Web will provide us the ability to lock in write mode the DOM, apply changes, and unlock it all at once, it will perform even more.

Is all that performance needed? No, this is a non real-world use case.

Do I need any virtualization on top to reach good performance?
No, again, no.

Is this FUD? I don't think so, so let's agree to disagree.

Andrea Giammarchi said...

Matt

> Most of these frameworks are far easier to read and write than native. You might disagree

I don't, otherwise nobody would even think about choosing abstractions.

I've written abstraction has good parts, I won't be the one doing the list in this thread though ;-)

kentaromiura said...

So, you are saying that an abstraction on top of the DOM is slower than the DOM, well, you know, it's just common sense, nobody ever wanted to say otherwise.

Not with that set aside and agreed by anyone, let's consider what this abstraction bring to the table and what's you can do with that.

So, for instance by being an abstraction, is possible to change the medium of the render function, so instead of using the DOM, one can render on a canvas, as the Flipboard team did with https://github.com/Flipboard/react-canvas, is theoretically possible to use webgl and use the 3d acceleration, breaking the boundaries of what you can achieve using just DOM.

The best thing is that those abstractions enforce people to use some specific patterns, which could be better of whatever they are using at the moment.
Because libraries comes and go, good ideas and patterns remains.

For performance, my though about that is that you shouldn't do premature optimization, and just optimize where you really need.

I take the Atom editor for example, when they switch to React they gain some performance benefits:
http://blog.atom.io/2014/07/02/moving-atom-to-react.html, then they notice the pattern react was doing to modify the DOM, and notice there were further possible optimizations so they decided to remove react in their editor: https://github.com/atom/atom/pull/5624
what this means is that from this we gained a very good performing editor, which is improved by the adoption of a library and was probably this that lead the team to their solution, which is way better of their original one.

In the specific case of react I think the team supports up to IE8, which probably lot of mobiles as well as probably other using some poly.

As for file size, react minified is 140K, which is around 36 gzipped, I bet is probably smaller than some images of the average website.

Bottom line, I agree with you, use whatever you think is the best tool available to you, learn what are the downsides and the upsides and choose carefully, you can always go back to the good ol' DOM if needed (just remember to minimize the operations, use documentFragment, move around available nodes with appendChild, the difference of the Table Object Model and the existence of the CSSOM etc. etc)

Andrea Giammarchi said...

last one for Rich:

I've said that because I've been there.

I'm a very pragmatic person, and I want to be able to get out of the box whenever it's more convenient, easier, and also faster.

I've had to find so many compromise with teams I've worked with because "that's not the framework we are using way", where the framework itself wasn't necessarily better, more elegant, or more readable.

Developers that cannot choose are developers able to put themselves in troubles and often incapable of getting out of troubles.

Being religious about a FW and/or a style is a scary way to work I personally don't like.

"This is the way of the framework" when the DOM is already an abstract framework full of potentials few frameworks don't even know, is an anti-learning pattern.

At some point I wanted to write a post on how many developers know that your listener could be an object, instead of a function.

This will break in so many frameworks 'cause maybe even core-team members didn't know ... that's a missed opportunity for stateful interactions, but of course the FW would have reinvented the wheel for states ... I hope you better understand what I mean and why I wrote that.

Does religious "framework or nothing" scares me? Yes!

Is that common? Be honest and try to tell me is not ...

Andrea Giammarchi said...

Cristian a website in a canvas in a terrible idea for everything: SEO, a11y, older browsers ... CSS capabilities, I don't think there's an end to the list of problems you gonna have.

Yes, it might be required for games on canvas, but that's another story, and I'm not sure anyone is using Virtual DOM there. Physics engines are ... you know, more useful.

About premature optimization, the entire "use Virtual DOM" propaganda is indeed what I believe is a premature optimizations based advice.

Even if I have the slowest of the frameworks I can simply drop it for that component and use just the DOM, I don't need to bring in a new framework.

If you were instead actually referring to my code-style, I'm afraid when I code for myself it comes out like that, and the code itself wasn't the point if not that you don't need 140kB or gzip compression to run it, and it works in at least all React supported devices but I believe even more.

You know what? I am going to test those 3 old fellas, let's see how it goes.

Best Regards

Andrea Giammarchi said...

here, we have a bench where it matters the most: crappy hardware, the one that needs performance for real, and not just on paper.

Unknown said...

Thanks for posting the video - are they both Android 2.3, or two different versions?

Andrea Giammarchi said...

Samsung on the left is Android 2.3.4, while the phone on the right is the gorgeous Palm 2 webOS 2.2.4

It's funny, the only one showing something, is the one with basically 0% of market share, while Android 2.3 is still at 6.4% of Androids out there.

Now, some might say "who cares", the thing is ... I had to do nothing to make it work, beside giving a basic rAF shim

flam said...

Reading these comments gave me a heart ache lol.

Poor Rich from the RACTIVE*** team.

Andrea Giammarchi said...

I swear it wasn't my fault ... I just used saame object, and realized during the video it was mispelled!

Mike Parsons said...

Interesting discussion ... this is a technique I use when I need maximum performance ...

http://mparsonsvm.cloudapp.net/dbmonster

It leverages CSS, which utilizes the GPU with close to zero DOM updates so it's very fast as well as has a very low memory / cpu profile.

Plus it doesn't use any framework and is only a few lines of code.

It's not for every scenario but it works very well in a large number of use cases like this sample.

Andrea Giammarchi said...

Mike, that shoes the same thing in every cell .. am I missing something?

Mike Parsons said...

That's just to show the UI speed/responsiveness. You can bind to different values simply by updating the attribute on each cell and then rebind using document.styleSheets[2].addRule('td::before','content: attr(id);')

or whatever attribute you want.

The sample is meant to illustrate that you don't have to interact with the DOM or the Virtual DOM to display data in a very performant way.

Andrea Giammarchi said...

I'm not sure I understand ...

> You can bind to different values simply by updating the attribute on each cell

How is this "non iterating with the DOM" ?

Can you please crate a 1:1 comparison of this benchmark, or you are talking just theoretically?

I understand using just is an option but I'm not sure it will perform better, since repaint and DOM access is still needed, plus it will completely miss the backward compatibility point, working ony on modern devices, where performance is not even a real world problem.

Thanks

Andrea Giammarchi said...

* using just CSS