Tuesday
11
Oct 2005

The tale of two worlds - JavaScript OO performance in Firefox and IE

(8:58 am) Tags: [Software, Rants, Projects, FeedLounge]

After looking at the source for Mochikit, Dojo, Prototype and others, I decided that FeedLounge could use a bit more object-orientation in the client side code.

I created a simple object structure, and wrote a few little test scripts that I ran in the browser. Since I subscribe to 1500+ feeds in FeedLounge, the feed loading/processing on the client side is getting quite slow, so I wanted to make sure that this refactoring was going to help and not hinder client-side performance.

While the test results show what I have built will help performance quite a bit (no more looping over DOM nodes, looking for the right one), the results were a bit surprising…

Given 2 objects, feed and tag, where a tag can contain feeds, I wrote a simple loop to create n feeds, and set an unread count on the feed, then add that feed to a single tag (the worst case in FeedLounge). I wanted to make sure that this solution would scale for the power user, so I started the test at n=5000.

At 5000 feeds to a tag, Firefox was running the code in less than 1 second, which seemed acceptable, so I bumped up n=50000. Firefox choked saying “Out of memory”, so I dropped it in half to n=25000.

The loop at 25000 took 3 seconds of full CPU to run, and the count items return was quite quick. On to test IE, since we support more than just one browser…

In testing IE, I was shocked to find it taking 3 minutes at 100% CPU to run the loop at n=25000. It did eventually finish, but while I can justify 3 seconds on initial home page load to my users, I don’t think they will stand for 3 minutes! I also noticed that memory consumption in IE was over 3 times as much as Firefox. For n=25000, the delta in Firefox had been 50MB. That seems like a lot, but I also didn’t see many people subscribing to 25000 feeds. In IE, the memory usage was 160MB!

Does anyone have any ideas in how to optimize JavaScript for IE? I am doing some extremely simple things here, nothing rocket science at all.

I am not too terribly worried, as the patch for power users of FeedLounge is to switch to Firefox :)

Popularity: 40%

17 Responses to “The tale of two worlds - JavaScript OO performance in Firefox and IE”

  1. Chris Meller Says:

    Heh… ‘patch’… ‘Service Pack’ may be a slightly better analogy.

    While personally I think everything should be created Firefox-only, just to screw IE users over (and therefore encourage converts), let’s be realistic here. Last I heard, even Scoble only had 1500 feeds… What is this 25,000?? Don’t you think we’re getting a bit excessive in the name of testing for the most extreme scenario?

  2. Scott Sanders Says:

    Chris,

    2500 feeds in IE still takes over 9 seconds to count. That is still in the ‘unacceptable’ realm for a lot of users. They will tend to think that FeedLounge is broken.

    And yes, I also would prefer “Service Pack”.

    I am glad Scoble and I have something in common :)

  3. Scott Sanders Says:

    And did I mention part of my building FeedLounge is to push my 1500 subscriptions up to 15000 or more? Call it FeedLounge 2.0.

  4. Chris Meller Says:

    I agree that 9 seconds for 2500 is still unacceptable, I was just a bit surprised at the 25,000.

    And we’ll never let you get up to 15k. At that rate, we’d never get any work out of you! :)

  5. Scott Sanders Says:

    The point is that 15000 tomorrow should be as easy at the 1500 today…

  6. Hermann Klinke Says:

    I would call this premature optimization…The advantage of web deployment is that you can do it anytime.

  7. Sebastian Werner Says:

    Please tell some detail. In my opinion and researches for qooxdoo I have detected that the loops in IE are only 2 times slower than in firefox. More problematic is the content of the loop. What do you do inside the loop? String concats or generally strings are really problematic. If you post the code or send it to me I can take a look at it.

  8. Scott Sanders Says:

    Herman,

    I would say that it is not premature optimization, as the previous solution we were using in feedlounge ran over the script max time limit default in firefox quite often, and with my account having 1500 feeds, the new solution still runs over the limit. We are really pushing what JavaScript can do, from a performance/size perspective.

    Sebastian,
    There is almost no string concatenation in these tests. Just simple JavaScript object creation, setting a few properties on each object created. The code I used to run the test is here. Just increase the loop iteration value.

  9. Sebastian Werner Says:

    If you remove the first four lines of your testfile in the class Feed try it again.

    /*
    this.className = “fl.Feed”;
    this.id = id;
    this.title = “”;
    this.rssLink = “”;
    */

    The change breaks probably the code somewhere, but in my example with 2500 iterations (not changed) it reduces the runtime from 8500ms to 250ms in Internet Explorer.

    As I said previously in IE the most important thing is to remove strings.

    Please try it your own.

  10. Scott Sanders Says:

    Therein lies the problem, Sebastian. Removing the strings will break FeedLounge completely. I don’t think I am clever enough to do it without strings ;)

  11. Alex Says:

    I don’t think those nodes will be very useful unless we can set their properties.

  12. Chad Whipkey Says:

    Commenting out that code improves the time greatly, but not because of strings. Commenting that code out makes all Feed objects have the same id. This causes only one of them to be added to the dictionary (which cuts down on the number of DictEntry objects being created).

    I think you can get a speedup by moving the functions out into global variables and then assigning them. IE is probably allocating a new object each time you define the function. The same may be true for string assignments as well (as Sebastian writes)–in that case, moving the string to a global may help as well (could actually hurt firefox since now it has to look the variable up in the global context).

    I did this change and got a 60% speedup on firefox and an 80% or so speedup on IE.

    For example:

    var gFnFeedRepr = function() {
    return this.className + “(” + this.id + “){” + this.tags.repr() + “}”;
    };

    fl.Feed = function(id) {

    this.repr = gFnFeedRepr;
    }

  13. Alistair Says:

    Not a solution, however you could stage the loads to make it smooth and progressive. Instead of trying to load a block of 10,000 feeds in one go; load them 1,000 at a time and make it smooth.

    Maybe give the user a little feedback saying:

    - Currently loading block: 3000-4000 (Total: 30%)
    - Currently loading feeds: an-az (Total: 13%)

    Just as an idea if you can’t make it process any faster than it already is.

    Al.

  14. Joe Roney Says:

    One of the factors here is that the javascript engine in IE seems to be poorly optimized for loops. The following code takes about 77 sec. to run through 10,000 checkboxes on my box:

    for (var i=0; i

  15. Joe Roney Says:

    Not quit that Fast…

    should been:

    “You can unpack this loop with something like the following (like Duff’s Device) which run’s through 10,000 checkboxes in about 1.08 sec. on my box:”

  16. Prasanna Nimmala Says:

    I have a issue similar to this. I’ve been working on a web page where I display 1295 records using javascript. In IE it is taking more than 2 min to display but in Firefox and Netscape its taking not less than 5 secs. Can anybody help me in solving this issue. Fallowing is the code of that function.

    function createTable(holderId, dataAry, columnNames, colAlign, startRowIdx, endRowIdx){
    //Get number of rows/columns
    var rows = dataAry[0].length;
    var cols = dataAry.length;
    //Set defaults
    if (startRowIdx == undefined){
    startRowIdx = 0;
    }
    if (endRowIdx == undefined){
    endRowIdx = rows;
    }
    //Create table HTML
    var string = ‘’;
    string += ‘’;
    for (var i=0;i‘ + columnNames[i] + ‘‘;
    }
    string += ‘’;
    var rowClass = “Row-Results-Dark”;
    var rowCnt = 0;
    var rowVisible = true;
    for (var i = startRowIdx; i ‘;
    for (var j=0;j’;
    try {
    string += makeTableCellContents(j, i, dataAry); // Method should be defined in user scripts
    } catch(e){
    string += dataAry[j][i];
    }
    string += ‘’;
    }
    string += ‘’;
    rowCnt++;
    }
    string += ‘’;
    //Add table to document
    document.getElementById(holderId).innerHTML = string;
    }

    Thanks.

  17. aresot Says:

    IE has very poor engine for allocating new objects. Seems if it goes above some threashold (7K) it slows IE to the crawl. this is why its deseiving to think that changing loops or pemoving some fields will solve problem since its (like someone pointed above) will make same object to be recreated instead of multiple.