Without a doubt, Prototype.js makes a developer’s life easier. Sometimes, though, it works so well and has so many useful functions, that we often don’t stop to consider the cost of using everything Prototype.js has to offer. One of my favorite, and most used features of the library is Enumerables. They have replaced standard loops in most of my code because they offer a lot more functionality and make everything a lot more legible. Even if the task in question did not need the additional functionality of enumerables, I still used .each for a basic loop to keep the code consistent. Unfortunately, this has turned out to be bad practice.

I just discovered that using enumerables is considerably slower than a traditional loop. While anyone could predict this off the top of their head, I didn’t quite realize the extent of the slowness. In an effort to validate the a bottleneck in one of my scripts, I ran some basic tests to see how much my program was hurting from the handy shortcut. I use a lot of nested loops for lookups, so the test was structured with two functions: one for normal loops, and one for enumerables. Here are the two functions I faced off:

Normal Loop:

function loopNormally() {
    var x = 0;
    for(var i = 0; i <p>

Array Elements For Loop Prototype .each 100 0.01 secs 0.277 secs 500 0.254 secs 3.251 secs 1000 0.484 secs 14.294 secs

The numbers above are the average of 3 runs of the test. I ran each test about 20 times to look for anomalies, but it’s fairly consistent. Also, the test with 1000 elements timed out for prototype, and required me to click “continue running script.” I also ran the tests with single loops (instead of nested) and got similar results.

The numbers are based off of Firefox XP. In IE, the prototype numbers are considerably faster - almost 1 second faster for 500 elements, and 3 seconds faster for 1000 (with a timeout still). Also, the numbers for a normal loop are slower - around 0.7 for the 500 element loop. Even though IE closes the gap, the difference is still substantial.

So, the lesson learned here is to only use the powerful functionality offered in Prototype when needed. If basic JavaScript will do the task, then use basic JavaScript.

HTML Form Builder
Ryan Campbell

Beware of JavaScript Library Overkill by Ryan Campbell

This entry was posted 4 years ago and was filed under Notebooks.
Comments are currently closed.

· 15 Comments! ·

  1. Dharmesh Shah · 4 years ago

    Thanks for sharing this. Very useful.

    I would also be interested in knowing what UI features of prototype.js you find the most useful.

    I’m exploring Javascript libraries for one of my projects and am trying to figure out what real people are actually using.

  2. Andrew Dupont · 4 years ago

    This is good advice, but I wonder if it’s a bit too Draconian — unless you’re building a really client-side-intensive web app, the performance difference should be negligible. Even in your shortest test you’re looping 10,000 times.

    The way I’d put it is a little more wishy-washy: when you’re trying to improve performance, converting Prototype each methods to boring, old-fashioned for loops is a good starting point. Figure out where your code loops the most and optimize those parts.

    Those tests are surprising, though. For comparison’s sake, how about doing a couple tests where only one of the nested each loops is converted to a for loop? I imagine converting the inner loop would save you some precious cycles.

    Also, what were the exact numbers on the single-loop tests?

  3. Kumar · 4 years ago

    “Beware of JavaScript Library Overkill.”

    I find the title of this article a bit misleading. I came expecting an article on how js libraries are over-used in many cases and file sizes are adding up and using more bandwidth…

    I only have a couple years of java experience, but even in an introductory class they tell us to use enumeration with caution… however this was a good read, especially the part about ie closing the gap… =P was that in ie5/6 or 7?

  4. Wolfgang Bartelme · 4 years ago

    You should also avoid using “getElementsByClassName” too frequently. It also slows down the script significantly.

  5. Sebastian Werner · 4 years ago

    Generally this is true, but only in cases where you really need the performance. The most time this is not especially needed and than nice looking code is better than optiomal coded ugly looking code.

    Just my 2cents.

  6. Arthur · 4 years ago

    Even though my AI in JavaScript is being spread around the Web to such sites as http://saintstephen.memebot.com/aimind/index.html I am still a rank beginner in JavaScript and I did not even know that JavaScript had libraries, so I am thankful for the information.

  7. Greg Benedict · 4 years ago

    Accessing forms with $F(id) is very heavy as well. We’ve been working on a revenue/expense forecasting application for a customer that will run on IE 6 on hardware that is 3-4 years old. In firefox it was barely noticeable, but in IE it was nearly 14 seconds to run the new calculations when you changed values. Once we pulled it out and did a more direct style of access, document.forms, it was down to about 2.5 seconds. That’s a huge difference.

    I love prototype for it’s simplicity, but you have to watch out on large/complex pages. Even with the latest and greatest version, IE still bleeds a large amount of memory.

  8. Ryan Campbell · 4 years ago

    Kumar, it was IE6.

  9. Thomas Messier · 4 years ago

    I’ve actually been wanting to become an Enumerable convert, and you haven’t discouraged me. More complex functionality is bound to lead to slower results, but it’s usually negligible for most applications. However, thanks for doing that, because in the event that I do something dealing with more data, I’ll already know where my problem lies.

  10. Mislav · 4 years ago

    Ryan, while you’re doing these test it would be neat to test javascript 1.7 iterators in Firefox 2!

  11. Andrew Kumar · 4 years ago

    Thanks m8!

  12. Justin Palmer · 4 years ago

    Ryan, great post, and a friendly reminder that when performance is top priority, anything that isn’t native will be considerably slower than a custom solution.

    Firefox, Webkit, and Opera(to some extent) have support for Iterators like forEach, map, etc. I think we’ll probably see future versions of Prototype delegate to these native methods in future releases.

  13. Cory Hudson · 4 years ago

    Thanks for showing us these stats. The reason Prototype’s each is so slow is that for every iteration through the loop, it runs a try/catch block around the function you passed in. Why? Because it emulates using break and continue statements. The catch is that to use them you have to use “throw $continue” or “throw $break” in your loop function to mimic the native functionality. It’s actually a rather ingenius solution, it just comes with a big performance hit.

    I talk a little bit about this and the new mootools JavaScript library’s own each method at:

    http://www.coryhudson.com/blog/2006/09/14/useful-utility-functions-in-mootools/

  14. Gal Steinitz · 4 years ago

    Another problem with the .each method is that regular error exceptions aren’t thrown, presumably because of the mechanism Cory Hudson described above. I had to had my own try/catch block around my code just to get a little error reporting.

  15. fritz from london · 4 years ago

    I just discovered that using enumerables is considerably slower than a traditional loop.

    Well done Sherlock! Next week: Ryan Campbell discovers tea is much nicer when made with hot water instead of cold ;-)