Performance Comparison of Event Handling Techniques Across Popular Browsers
If ever you decided to fancify your JavaScript by separating it out in a clean manner, using “unobtrusive” techniques such as Behavior.js or UJS, you hopefully didn’t attempt to apply them using something like prototype’s Event.observe. Although perfectly workable for limited JS interaction, such libraries very quickly grind even the most efficient browser into the ground when applied to huge numbers of elements.
In this post I attempt to identify the most efficient method of event handling, putting all other considerations other then raw performance aside.
Incidentally, I got to experience first hand that Steve was right, Safari 3 really is the fastest browser in existence today, and Joel was wrong.
The Actual Tests
Nothing: Benchmark for the plain HTML page without any events attached. (It’s a pretty big page, containing several nested divs and input elements)
Only Callbacks: Plain HTML page with a callback function after each element. The callback itself only reads the element by ID. This is needed to measure the impact of using callbacks to initialize events for elements right after they are loaded. It is almost certainly faster then looping over a pre-defined list of elements.
Traditional: Uses the callbacks to assign old-school style event handlers from JS – like element.onclick= function(){...}
DOM: The modern, “recommended” way, using addEventListener.
Observe: Use prototype’s Event.observe(), which in turn uses addEventListener but adds extra functionality (and also makes it work in MSIE)
Inline: Use inline event handlers such as <div onclick="...">.
Delegation: Use event delegation, where only window.document handles events. It can then find the originating element using the event object, and then fire any registered callbacks.
| Event method / browser | Safari3/OSX | Firefox2/OSX | Opera9/OSX | IE7/Vista | Firefox2/Vista | Safari3/Vista | IE6/XP |
|---|---|---|---|---|---|---|---|
| Nothing | 133 | 2,769 | 510 | 374 | 4,506 | 402 | 406 |
| Only callbacks | 381 | 12,957 | 6,394 | 29,498 | 20,509 | 791 | 44,118 |
| Traditional | 651 | 13,899 | 9,700 | 104,333 | 25,149 | 1,308 | 128,625 |
| DOM | 652 | 17,292 | 23,851 | n/a | 24,646 | 1,279 | n/a |
| Observe | 1,569 | 16,725 | 70,187 | 118,614 | 23,958 | 2,436 | 223,735 |
| Inline | 189 | 3,721 | 1,230 | 1,378 | 5,081 | 1,258 | 17,140 |
| Delegation | 146 | 3,001 | 463 | 550 | 4,156 | 567 | 172 |
(Results are page load benchmarks in milliseconds – smaller numbers are better)
Unfortunately, I can’t (easily) post the test pages themselves – they were haphazardly generated from a rails app. You’ll just have to trust my methodology on good faith.
Different browser/OS combos ran on different computers, although I kept all the Vista ones on the same machine for fun to figure out who really wins the performance pissing contest. Congrats WinSafari, HIG breaking as you may be!
Interpretation
I was surprised to learn that inline handlers are not the most efficient. They almost
are, but not quite. Delegating events is, in theory, the best
performing, however, this method of event handling also has a number of
special caveats: The actual event delegation mechanism, could
be inefficient depending on how you build it. So although the page-load
impact is minimized, actually performing an operation after a click
could entail looping over a large array of functions and thus be a lot
slower then just calling handlers registered using addEventListener.
On
the other hand, delegation also makes it much easier to attach events
based on patterns such as class names. Attaching events using
prototype’s $$() selector function is notoriously inefficient, but could be nigh-instant using delegation. However, very common events such as mousemove fire so often that even relatively efficient pattern-matching functions could gum up.
Of course the second-best choice, inline handlers, is also the ugliest to work with, although server-side tools can make it more workable.
So really it’s a tossup between inline and delegation depending on your needs, provided you are working with very large, complicated pages. For smaller, simpler Java-Script, Event.observe() etc are quite sufficient.
- read more
- 18 Jun 2007 20:27
Copyright © Intractable Complexity
Powered by Typo