The DOM isn't slow
blog.korynunn.com
blog.korynunn.com
There appears to be an uptick of hyper-agressive technical posts over the past several years. I'm not sure where it started, but I'm hoping it burns itself out soon.
(If you're the author, I apologize for calling you out on this. Nothing personal at all, I just wanted to make the general point about tone.)
Look under DH2.
I didn't find his tone offensive at all, esp as a piece of writing. It's likely that he hears "DOM is slow" all the time, and is venting. And he's a far cry from Zed Shaw's kind of writing.
“I’m too stupid to know that what I’m doing is stupid”
I agree that the OP's smartass writing style is more annoying than anything else, but I really didn't like the quoted phrase above. Calling someone stupid because they don't know the ins and outs of what is, let's face it, a particularly byzantine system, is just, well...mean.However, if you'd prefer a critique on the substance of the actual article, I have one of those, too: https://news.ycombinator.com/item?id=5401340
He's saying it's more difficult to convince people of your point if you're being a dick about it. You aren't arguing the central point of his thesis, so I'm unsure what exactly your point is in regards to OP.
As far as I know, PG's post doesn't apply to the original article, as the article starts the discussion, rather than responds to one.
That said, the following things irked me:
> Abstraction is more likely to increase speed, because someone smarter than you has written the bit that needs to be fast.
That's a very sweeping statement that doesn't really describe the situation. It obviously depends on what you're doing, who wrote the abstraction and how much is being abstracted.
> First: ignore pretty much anything Facebook has to say about DOM performance. They really have no idea what they are talking about. Sencha was able to make a version of the Facebook mobile app with their framework, and it was FASTER than the official, native app, and Sencha isn’t even particularly fast.
If you create an app that has half the feature set of another app it will likely be easier to make it go fast.
> Second: Stop using DOM libraries out of habit! If your target browser is IE8 or above, jQuery hardly provides any features that aren’t shipped on the host object anyway. document.querySelectorAll will pretty much do everything you need. jQuery is a tool, not a framework. Use it as such.
jQuery provides a clean sensible API. Something that is currently still lacking from the DOM (despite all the improvements). document.querySelectorAll will definitely not do "pretty much everything" you need out of the box.
document.querySelectorAll doesn't even support event listeners or forEach loops. I wouldn't call that extra functionality, I'd call that a basic requirement.
It lets you select elements using CSS selectors. That's good and all but if you want to actually do anything with that you're better off using some sort of library that abstracts the awkwardness away (i.e. jQuery).
document.querySelectorAll("td").map(function (elm) { console.log(elm); })
But apparently a nodelist isn't array enough to get the map function. sigh....you could use Array.prototype.map.call(). But this really underlines the value of jQuery: in jQuery you can predict what will happen, in the DOM you can't.
(Note: I am aware you can alleviate this with toArray type utils [1] but that does seem to be slightly besides the point).
Am I the only one that hates this meme? The idea that "someone smarter than me therefore blah blah" seems ultimately to be counter-productive. Placing arbitrary limits on yourself does nothing except prevents you from attempting certain types of "hard" problems because "someone smarter than me will/couldn't figure it out so I shouldn't bother". Perhaps its just hubris on my part but I am completely confident in my ability to fully comprehend any problem or solution that someone has come up with. There are certainly people much smarter than myself, but I will never let that limit me. Whether or not there is actually a limit to what I am capable of understanding is irrelevant, I will never assume before-hand that something is beyond my comprehension or capability.
Save me from unrolling loops and implementing hash maps. I can do these things, I just do not want to.
Of course, I've seen programmers use the term "someone smarter than me" quiet literally. I'd agree with them, because what usually happens is a horrible anti-pattern.
I'm not that stupid, and I'm not that smart - I can figure out pretty much anything out there given time and effort.
Firstly, the assumption is that the "smarter" person has been focused on performance, rather than for example stability or flexibility. And more specifically, on performance for my particular use case.
Secondly, when I'm writing a native app, regardless of platform, I'm also using a set of OS libraries that have been written those "smarter" people.
And thirdly, if I'm looking to do something where speed is likely to be an issue (e.g. game development) I've got OS- (and use case-) tuned libraries, such as Cocos, that will have also been written by smarter people.
That was impressive on a 486 SX. The things that make people go "woa!" in a browser are, barring WebGL demos entirely made in shaders, completely not-impressive when compared to doing the same outside a browser. This is fine. The browser is expected to handle so many wildly varying use cases at once, it can't be top speed at all of them. But don't go around telling us that something that Firefox does on a 2Ghz quad core PC is amazing when the same has been done on an Amiga 500.
The DOM is slow. It can be used to be fast enough for most purposes.
What is the use case for generating 2000 unstyled divs with one line of text? Try making that into a nice slick CSS list, maybe throw an image in each list item, with some title copy and supporting text. Perhaps you throw a bit of text shadow on it to create a nice beveled effect. Oh yeah, that 2000 divs per 200 milliseconds probably just turned into 10. Maybe even less, maybe 1 or 2 on a mobile browser.
WebGL can gain acceptable performance in many situations, but there is still much overhead.
I suspect today's most web developers don't know the true performance of computers they are actually using.
Someone has already written a decent JSPerf to test this out: http://jsperf.com/innerhtml-vs-createelement-test/16 (see also http://jsperf.com/innerhtml-vs-createelement-test/4 for a slightly deeper dive)
Based on the Browserscope results (and my own testing), it seems that document.createElement is faster in Webkit but slower in everything else (Gecko, Trident). So, a bit of a wash there unless you're targeting mobile.
That said, in my experience HTML (template) parsing isn't the main bottleneck to getting an app to that smooth 60fps feeling. Usually the big targets you want to focus on there are avoiding cascading reflows/repaints, using smoother animation technologies such as requestAnimationFrame or CSS transitions/animations, understanding how to trigger hardware acceleration and what its limits are, and keeping careful control of your CSS special effects (border radius, box-shadow, gradients, etc). I recommend checking out http://jankfree.com/ (especially the I/O talk) if you're interested.
(edit: I don't really like the original article's vitriol, but he's right about a couple things. Manipulating your nodes outside of the DOM is much faster, although you don't need to be inside a DocumentFragment to do this (don't get me wrong; DocFrags are pretty useful). Also, yes, please don't keep running those jQuery selectors over and over again. Store the jQ object that the selector returns to you and just reuse that)
> People often throw around the statement “The DOM is slow”. This is a completely false statement. Utterly stupid. Look: http://jsfiddle.net/YNxEK/. Ten THOUSAND divs in about 200 milliseconds.
How is that even an argument? Just because you can insert a fragment containing 10k <div>s in 200 milliseconds doesn’t mean that the DOM is not slow compared to other operations in JavaScript.
DOM operations are still the slowest operations you can perform using JavaScript in a web browser.
You aren't refuting the author's point. "The DOM is slow" is based on an absolute timing. No one is making a relative comparison.
In general its possible to argue that operation X is fast, even if X is the slowest of a set of operations, if you take an absolute perspective.
If you’re calling JavaScript features slow or fast based on absolute measurements, you’re doing it wrong. Read up on JavaScript benchmarking. Create and run some jsPerf tests on various devices and browsers, and compare the results. You’ll quickly find that absolute numbers are meaningless in this case.
This article is correct, and provides an example, in saying that the DOM can easily create thousands of elements in milliseconds. However, the problem is that events and interactions with it all happen on a single process. Things load and block the thread, an event happens and blocks the thread, etc.
The Sencha guys did something really smart. They used an object pool with one object: requestAnimationFrame, as the core of their mobile platform and sent EVERYTHING to it. That way events, loading, or whatever, didn't block, but happened in a FIFO manor. They also kept the number of dom elements static and just reused them when needed, so an object pool of dom nodes -- no creating or destroying nodes.
The things that make working with the dom slow isn't only creating nodes, but applying styles, listeners, and destroying them -- basically creating an application.
I do agree with the overall premise that a lot of developers do not know the best methods/practices/patterns to utilize when creating complex applications. I learn new things daily and I hope that our community continues to teach itself and provide tools to make getting things done easier.
DOM and Javascript engines still need few more man-centuries of iteration to bring their performance closer to e.g. JVM which doesn't really require hacks like that anymore.
Is this the case?
I used to be pretty in-touch with Java, but haven't been keeping up from the release of 7 onwards. I've picked it up again for game development, and 100% of the performance advice I've found is to use object pooling... but nearly all of that advice is years old, and I have no idea if it still holds true for JRE7 or even JRE6.
It did strike me as something the JVM should be doing for me, so if that has been fixed, that news will be greatly welcomed by the Java game dev community.
-- Brian Goetz in 2005
http://www.ibm.com/developerworks/java/library/j-jtp09275/in...This article was also written when Java 6 was starting to get escape analysis, which can result in stack allocations in some cases.
I recall taking a course in 2008 or so (Java 6). We were doing a genetic simulation of sorts, and the professor recommended using an object pool to speed things up. I implemented one and observed no measurable difference in my code's performance (these were very small objects used over and over again evolving new organisms). I hooked up a profiler and used that to guide me to some areas that could be improved, and a valuable lesson was learned.
You dont have to use all these tricks when you use IOS or Android widgets.
And usually developping with Xcode or Eclipse IDEs makes the work far more easier than using any JS ide.
Instead of using Javascript for the UI i usually use it to implement bits of business logic , algorithms i can easily port from plateform to plateform , so i get native UI and portable JS libraries.
I havent gotten too deep in native development on either platform, but don't they prioritize tasks automatically? JS doesn't, using requestAnimationFrame and web workers is doing exactly that. Wasn't the main knock against Android's UI lag because everything happens once allowing blocking and it was addressed with project Butter?
That's pure premature optimization. I don't understand how people can still be making blanket statements about performance costs like this. Using jQuery to create HTML elements is fine. It's convenient and succinct, and it keeps your code consistent. Otherwise, you'll have two ways of creating HTML elements: one for when you are just creating an element, and another for when you need to use jQuery on it afterward.
But if you do hit a point where creating HTML elements with jQuery is slow, you optimize that point and leave a comment explaining why you're doing it that way.
People get these ideas in their heads that somehow they're going to be able to code everything super fast from the very start, and it's nonsense. All you're going to do is make it harder to maintain your project.
When you're working in the mobile web and performance is important you want to know what every line of code is doing. Your application is probably going to be a little laggy anyways, but at least you'll know why that is and know where to target to try and fix it.
Except that it's not, because you can use profiling in modern browsers to figure out where the time is being spent.
>It's probably that in order to gain the 'sticky' affect you want that jquery plugin you're using is listening to a window.onscroll or something, and unless you want to dig into the code of every library you're using you probably won't know why.
But that's not what the author is arguing, and it has nothing to do with adding elements to the DOM via jQuery vs via lower level methods.
Nope, sorry, 9 times out of 10 the provision is theoretical and the interface is garbage. querySelector is pretty much the only one which does not suck — hence it being used as an example every single time.
* Querying or altering elements? Verbose shit.
* Binding events? Verbose shit.
* Delegating events? You've got 2 different specs, the most recent one is unimplemented and the older one is prefix-implemented everywhere (and useless as far as I know).
* Inserting elements in a DOM tree? Oh boy you're going to have a fun time manually traversing crap until you can reliably use insertBefore.
* Creating a node with text in it? You're in for 3 different statements, and that's if you're not trying to add attributes as well
* Manipulating classes? Hello broken regex search&replace. Oh you're targeting IE9 anyway? Well fuck you still, because Element#classList is IE10+.
* Playing with data-* elements? I hope you like getAttribute, because Element#dataset is MIA in MSIE.
* And bulk operations? What, you think querySelectorAll or getElementsByClass is going to return an array? Dream on, you may get something array-like in DOM4 if you're lucky. That means IE15, maybe.
Every single time I tried to get by with raw DOM, I fell back on zepto or jquery, life's too short for shit APIs and the DOM is exactly that. I don't code in raw DOM for the same reason I've stopped coding in assembly: I value my life more.
Now there are issues with jQuery, but these issues are generally that jQuery makes it easy to do the wrong thing (it's important to note that it also makes it easy to do the right thing, and improves that all the time, the "ease of doing the wrong thing" is just a side-effect of making things easier in general, the library does not specifically drive the user to the wrong thing) (except for animation maybe) e.g. keep doing noop work on empty selections, repeatedly select the same elements over and over again instead of caching the selection or not realizing you're doing a batch operation of adding a class or event on hundreds of DOM nodes in a single line.
The DOM itself does not fix this, it just makes these things so incredibly and obviously painful you look for other ways to do it to try and slightly alleviate the pain.
You get the same result out of thinking, and not blindly using jQuery.each and the like.
edits: formatting, classes manipulations, data-* attributes, matches/matchesSelector.
You can't though, not even close. You can speed up your application significantly by using event delegation on a parent instead of binding an event to each element, but the raw DOM makes this a giant pain in the ass in the general case.
* I'm sure Matthew realises but just gave the first example that came to him.
var i = 100; while(i--) els[i].addEventListener("click",fn);
it'd be untrue jQuery is nowhere _near_ 100x slower. Profiling this is totally ridiculous because there's no use case that requires adding event listeners at a scale that could _ever_ be a performance concern, but anyway - http://jsperf.com/jquery-on-vs-native/3. So just 10x slower on even this - completely not performance critical and therefore nobody would bother optimising it - method.
However, throwing away jQuery for whatever reason (as we have on the iOS-only project I've been on for the last 3 months) doesn't necessarily mean you're stuck in verbosity hell. We just tried to look for the points where it seemed most verbose/painful and wrote thin jQuery-ish wrappers around native stuff... so, for example, there's a short alias for querySelector All which gloms `Array.prototype.forEach` onto the return value, and class manipulation functions, and a handful of other things. Last time I checked, the library fits on one screen and none of the functions are longer than 4 lines.
Not necessarily the right approach for every project, but neither has it been a descent into hell.
Interestingly, I've never found event binding to be a particular pain point; the thing I'm really getting tired of is writing `e.preventDefault()`, but jQuery isn't going to save me from that anyway.
Yes, jQuery is a time saving tool, and a really good one at that. The problem isn't jQuery, it's the developers that abuse it.
Oh.. Déjà vu...
It doesn't matter. When you have a non-trivial thing to render in a list, not just a div with text content, and you start to scroll the browser stutters. Even if the list isn't particularly long (< 50 items).
CSS animations are also rather slow in mobile browsers although this is getting better with every release.
I actually find it a little bothersome that so much browser development these days is focused on JavaScript performance and JavaScript alternatives whether it is Dart or asm.js or whatever... when the DOM is the primary reason lag exists.
He argues that the developers working on these browsers are optimizing them, and that we are not intelligent enough to trump their obviously superior coding skills. Well, I'm going to disagree outright on that point. Many of us are very talented.
Add Webkit on top of the Dalvik VM and android SDK, and fragmented device ecosystem, and we're talking major disparities between the way your HTML5 app is going to run on different android devices. I have seen HTML5 apps that work great on phone a and b, but not on c, because well, c has a different webkit version!
It's bad enough to have to write code for different browsers. It's really bad to have to write code for different browsers that will run on hundreds of different android devices.
Back to the point you made about optimization: don't you think the developers of the native SDKs are making optimizations, too? And the lower level means we're way closer to the metal, lower on the stack, and ergo: less complex.
I'd use HTML5 for a trivial app, like, a business's mobile website. But for anything serious, GO NATIVE!
Note, my answer is for mobile browsers, specifically android. Even iOS should be marginally better on this, but really I've only seen HTML5 kicking ass on desktop browsers. I've yet to be impressed by it in mobile.
EDIT: typo
Try the blog of one Paul Irish and spread out from there.
That's not quite true. They matter enough that WebKit is implementing them incorrectly because they can't figure out how to make a correct implementation performant enough...
Also, here are some articles I found in my links list:
CSS Stress Tester Bookmarklet (Copy into a bookmarklet. Then it will tell you the rules that are causing the most lag.)
javascript:(function(d){var s=d.createElement('script');s.src='http://andy.edinborough.org/Demos/css-stress/stressTest.js?_... es=d.getElementsByTagName('script')[0];es.parentNode.insertBefore(s,es);var doit=function(){if(window.stressTest){stressTest.bookmarklet();}else{setTimeout(doit,100);}};doit();})(document);
Old but still relevant I think: http://www.stevesouders.com/blog/2009/06/18/simplifying-css-... Text makes CSS slow (don't render too much): https://news.ycombinator.com/item?id=2232212 In general, following good guidelines might help: https://github.com/csswizardry/CSS-Guidelines
For some concrete numbers, I updated a JSPerf that I found to include a raw JS implemention.
http://jsperf.com/creating-dom-elements/8
I was caught off-guard by the results - it appears that (even after multiple runs) the raw JS implementation is ~100 times (times, not %) faster. Definitely surprised at the drastic difference, although someone please correct me if I missed something in these simple test cases.
This was with Chrome on Windows, by the way.
For 99% of the projects out there, jQuery is fast enough and it's productivity boosts outweigh any performance costs.
It was really laggy on Android, so no.
The native vs web argument has been beaten to death. It comes down to this: there is no perfect solution and everything has trade-offs (speed, quality, and cost). Use your brain and pick the solution that works best for the problem you are trying to solve. As much as web apps have replaced many things that may have previously been implemented as native apps on the desktop, there is still native development being done.
One of the first rules to being fast in a GUI of any sort, Web-based or otherwise, is simple: don't abuse the runtime. Objective-C's runtime isn't very pretty for performance either, which is why you use the provided APIs when you can. When you can't, you get the data out of the objects and into a more suitable format, work with them there, and put the result back into the objects for display. There were some truly egregious cases of runtime-abuse in the old days: the first OSX versions of OmniWeb come to mind. But the dev community eventually caught up. It's the same with the DOM.
That's the thing about jQuery-abuse. jQuery is a very, very good hammer: an awesome tool for working with the DOM. The problem comes when people start to think that every problem looks like a nail: they start using the DOM for everything, including things that it's just plain not designed for. And it works, more or less; it just doesn't work well. That's not a problem with the framework. It's a problem with the user.
His appoint about using document fragments, or some equivalent thereof that resides outside the main DOM, is a good practice to follow when there are a large number of serial changes to the DOM that in effect are only one change to the user.
Still I am curious in what the benchmarks actually say. The native DOM methods appear to return before rendering is done (at least in webkit). So when we get a 200ms benchmark for 10,000 divs I suspect there it is taking a longer than that to fully render.
The next missing piece is the ShadowDOM/Templates stuff coming down the pipeline, but sadly that will probably take just as long for mass adoption.
I'm not surprised to see a large amount of disagreement and anger, partly because it threw this post together pretty quickly and i probably didn't explain things as well as i could have, and partly because, well, a lot of people really just cant write fast web apps.
In no particular order i would like to address a few things (most of which were addressed in the article if you read to the end..):
1. I never said "don't use jQuery". What I was trying to convey was "don't use jQuery stupidly". 2. I never said the DOM was the fastest part of the platform, obviously it isn't, in fact it is one of the slowest parts. But then, I wasn't comparing its speed to the rest of the platform, but rather to human perception. It doesn't matter if DOM manipulation is orders of magnitude slower than object manipulation, because it is easily fast enough to do pretty much anything, on pretty much any device, if you know what you are doing. 3. The fact that you read hacker news is a good sign that this post wasn't aimed at you. The post was a vent from the frustration of hearing 'The DOM is slow' as an excuse by people with no idea what they are talking about. It's a belief that is just accepted by many who have had difficulties with web development in the past, without any investigation as to what the actual issue is.
One think I see people doing a LOT is DOM selection. I find the pattern poor generally. Think about the standard case for developing 'web apps'.
1. Build objects in a server that describe the application. 2. Build a massive string from said objects. 3. Send it over the intertubes. 4. Give it to a browser, which then parses said string, fixes any errors you almost certainly made, then creates DOM elements. 5. Insert said DOM elements into the document. 6. Wait untill all of this is done, then use a tree searching algorithm to find said objects using jQuery/querySelectorAll/whatever. 7. Manipulate said object.
WAT. This seems a pointlessly convoluted pattern.
Alternative:
1. Build some objects on the server that describe the application. 2. Send it over the intertubes (Which will be faster, because a description of an app is going to be smaller than every little bit of it being sent) 3. Let JavaScript create DOM directly. No parsing, just pure DOM API calls. >>>Keep a reference to important elements.<<< 4. Insert DOM into document. 5. Work directly with the DOM elements. No selecting, no string manipulation, just normal object manipulation.
I look forward to the argument that ensues.
Writing this utilising jQuery for DOM manipulation ( http://jsfiddle.net/YNxEK/7/ ) is getting me consistently faster results than the original fiddle ( http://jsfiddle.net/YNxEK/ ) on Firefox and Chrome.
Here is the equivalent:
If you compare the DOM of the original fiddle and the DOM of following the fiddle I posted. You will see they are the same.
I'm not saying what I referenced is the 'best' way of doing things. But that the debate in the original article (based on the provided examples) is pretty null.
That way uses an indexed for-loop, but the while loop with Array.push was just as bad.
But checking at: https://blogs.oracle.com/greimer/resource/loop-test.html
Still seemed to demonstrate a decreasing while loop as the fastest in my test.
You call that impressive on 2013? My laptop can sort a million numbers in the times you can create a mere 10k objects.
>using JavaScript, render the whole thing in about 100 milliseconds.
That's not fast enough. 100ms is perceptible. Websites should render instantly, and 100ms is on top of everything else.
When selecting one DIV by id, I'm consistently getting:
DOM - 0.08ish ms
Jquery - 0.2ish ms
I do have an app where every millisecond is critical. For this app I'm using raw dom selectors. However, most of the time, the convenience of jquery selectors outweigh these performance gains.
[1] - http://jsfiddle.net/tolmark12/9R39R/ (open console)
Paragraph 1, sentence 2:
Capitalize "I" in "i would say"
Paragraph 2, sentence 3:
Capitalize "Chrome"
Paragraph 2, sentence 4:
Capitalize "Firefox"
Paragraph 3, sentence 1:
Should be "you're" in "your coding against the Dalvik" //Yes, this is fully valid JavaScript. Run it in the Chrome Web inspector, Firebug or similar.
Those who care to know if JS is valid already know at a quick glance. The preferred method of validation is JSHint or JSLint.Maybe not, but...
So condescending.