Mozilla faster than Internet Explorer

Discussion in 'Javascript' started by dhplank, Jun 2, 2005.

  1. dhplank

    dhplank Guest

    Hello everyone,

    I've developed a calendar program in javascript, and up until now I've
    done most of my testing using Mozilla and Firefox. Everything works
    fine, but when I try to use Internet Explorer my response time is
    sometimes 50 times slower than using Mozilla.

    I know I haven't given you much to go by, but I'm not looking for an
    answer so much as an approach to debugging the problem. For example,
    does anyone here know of a good web site which deals with
    browser-specific javascript performance issues?

    Thanks in advance for any helpful hints.
     
    dhplank, Jun 2, 2005
    #1
    1. Advertising

  2. dhplank

    RobG Guest

    dhplank wrote:
    > Hello everyone,
    >
    > I've developed a calendar program in javascript, and up until now I've
    > done most of my testing using Mozilla and Firefox. Everything works
    > fine, but when I try to use Internet Explorer my response time is
    > sometimes 50 times slower than using Mozilla.
    >
    > I know I haven't given you much to go by, but I'm not looking for an
    > answer so much as an approach to debugging the problem. For example,
    > does anyone here know of a good web site which deals with
    > browser-specific javascript performance issues?
    >


    Performance differences between IE and Firefox can sometimes be found
    in unexpected places. One strategy is to isolate loops and test
    them, then split them in half, then half again, etc. until the
    really slow bits are found.

    Replacing loops like:

    for (var i=0; i<someThing.length; i++)
    // mess with someThing
    }

    with:

    var i=0, x=someThing;
    do {
    // mess with x
    } while ( ( x = someThing[++i] ) )

    can cause dramatic reductions in processing time, particularly for
    large values of someThing.length.

    IE tends to be slower than Firefox at DOM operations, but can be
    much faster with some others (particularly string stuff in places).

    Once you've found the slow bits, post them here and you'll likely get
    something better, or just post some of your loops that you think may
    be the cause.


    --
    Rob
     
    RobG, Jun 2, 2005
    #2
    1. Advertising

  3. dhplank

    mike Guest

    <snip>
    Replacing loops like:

    for (var i=0; i<someThing.length; i++)
    // mess with someThing
    }

    with:

    var i=0, x=someThing;
    do {
    // mess with x
    } while ( ( x = someThing[++i] ) )

    <snip>

    Is this a "Noticeable" difference?
     
    mike, Jun 2, 2005
    #3
  4. dhplank

    RobB Guest

    dhplank wrote:
    > Hello everyone,
    >
    > I've developed a calendar program in javascript, and up until now I've
    > done most of my testing using Mozilla and Firefox. Everything works
    > fine, but when I try to use Internet Explorer my response time is
    > sometimes 50 times slower than using Mozilla.
    >
    > I know I haven't given you much to go by, but I'm not looking for an
    > answer so much as an approach to debugging the problem. For example,
    > does anyone here know of a good web site which deals with
    > browser-specific javascript performance issues?


    Not particularly browser-specific, but useful:

    http://www.peachpit.com/articles/article.asp?p=31567
     
    RobB, Jun 2, 2005
    #4
  5. dhplank

    RobG Guest

    Duncan Booth wrote:
    > mike wrote:
    >
    >
    >><snip>
    >> Replacing loops like:
    >>
    >> for (var i=0; i<someThing.length; i++)
    >> // mess with someThing
    >> }
    >>
    >> with:
    >>
    >> var i=0, x=someThing;
    >> do {
    >> // mess with x
    >> } while ( ( x = someThing[++i] ) )
    >>
    >><snip>
    >>
    >>Is this a "Noticeable" difference?
    >>
    >>

    >
    >
    > Only if '// mess with someThing' repeats the expression many times, e.g.
    > inside an inner loop.
    >
    > Simply replacing the for loop with:
    >
    > for (var i=0; i<someThing.length; i++) {
    > var x = someThing;
    > // mess with x
    > }
    >
    > will give the same speed improvements without the corresponding drop in
    > readability.


    No it wont. Getting someThing.length numerous times is slower than
    getting it once, so a similar 'for' loop is:

    for (var i=0, j=someThing.length; i<j; i++) {

    Using x to store the reference to someThing is faster than getting
    the reference every time. Initialising x with 'var' every time is not
    required but makes no difference to the speed as far as I can tell:

    var x;
    for (var i=0, j=someThing.length; i<j; i++) {
    x = someThing;
    ...

    Pre-decrementing i is also faster in most browsers (I believe Opera is
    slower in some circumstances), so a while loop can look like:

    var i=someThing.length;
    var x;
    while ( i ) {
    x = someThing[--i];
    // do stuff
    }

    or

    var i=someThing.length;
    var x;
    while ( i-- ) {
    x = someThing;
    // do stuff
    }

    But it iterates through the elements of someThing backwards (which
    often is not a problem, but may be if order is important).

    Anyhow, there are a thousand variations on the theme, have a read here:

    <URL:http://www.websiteoptimization.com/speed/10/10-2.html>

    There is a bug in the page, so download it and fix the bug, then run it
    (there's a form and a function called 'testLoop').

    Also try here:

    <URL:http://4umi.com/web/javascript/optimize.htm>

    >
    > There is one other way that the do..while loop gives a massive speed boost
    > though:
    >
    > if any of the array elements have non-true values the while loop will exit
    > when it hits the first one whereas the for loop will continue through the
    > whole array. Obviously aborting the loop after a single iteration instead
    > of 10,000 would give a noticeable difference. :^)


    Not necessarily, they will only exit early if the value of the element
    is (part of) the test, e.g.:

    while(someThing[++i]) or while(( x=someThing[--i] ))

    or similar. But there are plenty of ways to avoid that, e.g. the first
    two while loops proposed above will iterate over every element.



    --
    Rob
     
    RobG, Jun 3, 2005
    #5
  6. dhplank

    dhplank Guest

    Thanks to everyone for the many helpful hints. After reading throught
    the hints and performing various tests, I've been able to establish
    that the biggest part of the performance problem has to do with how
    Mozilla and Internet Explorer handle DOM (Document Object Module)
    obects.

    For example, the following bit of code:

    <CODE>
    for (i=1; i <= 366; i++) {

    if ((document.saisir["cal_yr1_type_jour_" + i].value != 35) ||
    (document.saisir["cal_yr1_active_jour_" + i].value == 0)) {

    document.saisir["cal_yr1_active_jour_" + i].value = 0;
    document.saisir["cal_yr1_type_jour_" + i].value = 0;
    document.saisir["cal_yr1_debut_jour_" + i].value = 0;
    document.saisir["cal_yr1_fin_jour_" + i].value = 0;
    document.saisir["cal_yr1_theor_jour_" + i].value = 0;
    }
    if ((document.saisir["cal_yr2_type_jour_" + i].value != 35) ||
    (document.saisir["cal_yr2_active_jour_" + i].value == 0)) {
    document.saisir["cal_yr2_active_jour_" + i].value = 0;
    document.saisir["cal_yr2_type_jour_" + i].value = 0;
    document.saisir["cal_yr2_debut_jour_" + i].value = 0;
    document.saisir["cal_yr2_fin_jour_" + i].value = 0;
    document.saisir["cal_yr2_theor_jour_" + i].value = 0;
    }
    }
    </CODE>

    takes 3.8 seconds under Mozilla, but 36 seconds under Internet
    Explorer. And in other cases I've found that Mozilla is as much as 100
    times faster than Internet Explorer.

    In some cases I've been able to better performance by assigning a DOM
    object to a variable which I then re-use. However in a case like the
    above this doesn't seem possible (since each object is only used once).

    Anyone have any ideas?
     
    dhplank, Jun 6, 2005
    #6
  7. dhplank

    Grant Wagner Guest

    "dhplank" <> wrote in message
    news:...
    > Thanks to everyone for the many helpful hints. After reading throught
    > the hints and performing various tests, I've been able to establish
    > that the biggest part of the performance problem has to do with how
    > Mozilla and Internet Explorer handle DOM (Document Object Module)
    > obects.
    >
    > For example, the following bit of code:
    >
    > <CODE>
    > for (i=1; i <= 366; i++) {
    >
    > if ((document.saisir["cal_yr1_type_jour_" + i].value != 35) ||
    > (document.saisir["cal_yr1_active_jour_" + i].value == 0)) {
    >
    > document.saisir["cal_yr1_active_jour_" + i].value = 0;
    > document.saisir["cal_yr1_type_jour_" + i].value = 0;
    > document.saisir["cal_yr1_debut_jour_" + i].value = 0;
    > document.saisir["cal_yr1_fin_jour_" + i].value = 0;
    > document.saisir["cal_yr1_theor_jour_" + i].value = 0;
    > }
    > if ((document.saisir["cal_yr2_type_jour_" + i].value != 35) ||
    > (document.saisir["cal_yr2_active_jour_" + i].value == 0)) {
    > document.saisir["cal_yr2_active_jour_" + i].value = 0;
    > document.saisir["cal_yr2_type_jour_" + i].value = 0;
    > document.saisir["cal_yr2_debut_jour_" + i].value = 0;
    > document.saisir["cal_yr2_fin_jour_" + i].value = 0;
    > document.saisir["cal_yr2_theor_jour_" + i].value = 0;
    > }
    > }
    > </CODE>
    >
    > takes 3.8 seconds under Mozilla, but 36 seconds under Internet
    > Explorer. And in other cases I've found that Mozilla is as much as
    > 100
    > times faster than Internet Explorer.
    >
    > In some cases I've been able to better performance by assigning a DOM
    > object to a variable which I then re-use. However in a case like the
    > above this doesn't seem possible (since each object is only used
    > once).
    >
    > Anyone have any ideas?


    Yes, take the suggestions that have already been offered and remove all
    those accesses to document.forms['saisir'].elements[your_elements],
    cache a reference to the elements collection and use it directly. Also
    reverse the direction of your loop (not that it makes much difference,
    but when dealing with UI, every millisecond counts):

    var f = document;
    if (f && (f = f.forms) && (f = f['saisir']) && (f = f.elements)) {
    for (var i = 367; i-- > 0;) {
    if (f["cal_yr1_type_jour_" + i].value != 35 || /* etc */) {
    f["cal_yr1_active_jour_" + i].value = 0;
    // etc
    }
    }
    }

    --
    Grant Wagner <>
    comp.lang.javascript FAQ - http://jibbering.com/faq
     
    Grant Wagner, Jun 6, 2005
    #7
  8. dhplank

    dhplank Guest

    >> Yes, take the suggestions that have already been offered and remove all
    those accesses to document.forms['saisir'].elements[your_elements],
    cache a reference to the elements collection and use it directly. <<

    By taking into account all the suggestions offered, I've managed to
    dramatically improve performance. Most transactions now take less than
    one second, which is acceptable in the context. Caching the DOM
    references is what really speeded things up. I found though that I
    have to cache each reference, not just a reference to the form, in
    order to get significant improvements.

    This means though that I still have one bit of code, which is used to
    initialize the page, which is rather slow - it takes about 36 seconds
    under Internet Explorer (and only 3 seconds under Mozilla). This bit
    of code will only be executed one time per session, so perhaps I can
    live with it, but it would be nice to speed it up if at all possible.
    Here it is:

    <code>

    BeginBench();

    // Cache DOM values for reuse.
    for (i=366; i >= 1; i--) {
    c1ac = document.saisir["cal_yr1_active_jour_" + i];
    c1ty = document.saisir["cal_yr1_type_jour_" + i];
    c1de = document.saisir["cal_yr1_debut_jour_" + i];
    c1fi = document.saisir["cal_yr1_fin_jour_" + i];
    c1th = document.saisir["cal_yr1_theor_jour_" + i];

    c2ac = document.saisir["cal_yr2_active_jour_" + i];
    c2ty = document.saisir["cal_yr2_type_jour_" + i];
    c2de = document.saisir["cal_yr2_debut_jour_" + i];
    c2fi = document.saisir["cal_yr2_fin_jour_" + i];
    c2th = document.saisir["cal_yr2_theor_jour_" + i];
    }

    EndBench("InitRules3");

    </code>

    (By the way, the DoBench and EndBench subroutines are just used to time
    the code.)

    I need to work with the hidden "input" fields in the HTML form, as the
    whole form is later sent to a parser which recovers everything and
    inserts it into a database. I don't think it's feasible to change the
    design approach - too much other code is involve.

    So ... any ideas on how to reduce the initialization time of this loop,
    or am I just stuck with it (get or take a few milliseconds)? Would
    getting rid of the loop significantly speed things up? (I might try
    that to see.)
     
    dhplank, Jun 9, 2005
    #8
  9. JRS: In article <>,
    dated Thu, 9 Jun 2005 02:51:10, seen in news:comp.lang.javascript,
    dhplank <> posted :


    > // Cache DOM values for reuse.
    > for (i=366; i >= 1; i--) {
    > c1ac = document.saisir["cal_yr1_active_jour_" + i];
    > c1ty = document.saisir["cal_yr1_type_jour_" + i];
    > c1de = document.saisir["cal_yr1_debut_jour_" + i];
    > c1fi = document.saisir["cal_yr1_fin_jour_" + i];
    > c1th = document.saisir["cal_yr1_theor_jour_" + i];
    >
    > c2ac = document.saisir["cal_yr2_active_jour_" + i];
    > c2ty = document.saisir["cal_yr2_type_jour_" + i];
    > c2de = document.saisir["cal_yr2_debut_jour_" + i];
    > c2fi = document.saisir["cal_yr2_fin_jour_" + i];
    > c2th = document.saisir["cal_yr2_theor_jour_" + i];
    > }



    >So ... any ideas on how to reduce the initialization time of this loop,
    >or am I just stuck with it (get or take a few milliseconds)? Would
    >getting rid of the loop significantly speed things up? (I might try
    >that to see.)



    Your document.saisir must be an [array] Object; that code must look
    up saisir in document (and there's no doubt a lot there) 3660
    times. Try
    It = document.saisir
    ....
    c1ac = It["cal_yr1_active_jour_" + i];
    which should help.

    AIUI, i=366 ; do { ... } while (--i) could be a *little* faster.


    You create elements in 10 arrays; it **could** be better, or worse, to
    use one array, loaded with a ten-item object - later instead of
    clth you'd write A.clth .


    You're doing calendar work, AIUI. BE SURE, if you are using Date
    Objects repeatedly, to do your calendar in UTC rather than in local
    time; if your systems are anything like mine, UTC is several times
    faster IIRC. Read my site. Also, date objects may not be particularly
    fast in comparison with efficient coding (e.g. for month-length); read
    my site.

    --
    © John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4 ©
    <URL:http://www.jibbering.com/faq/> JL/RC: FAQ of news:comp.lang.javascript
    <URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
    <URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
     
    Dr John Stockton, Jun 9, 2005
    #9
  10. dhplank wrote:

    Please provide proper attribution.
    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    >>> Yes, take the suggestions that have already been offered and remove all

    > those accesses to document.forms['saisir'].elements[your_elements],
    > cache a reference to the elements collection and use it directly. <<


    Please learn how to quote in Usenet. `>>'...`<<' is not a widely accepted
    quotation style, for one part that it confuses parsers designed to
    recognize levels of quotation by one more leading character (usually `>')
    and thus allow user agents to format the levels differently.

    <http://jibbering.com/faq/faq_notes/pots1.html>

    > [...] Caching the DOM references is what really speeded things up.
    > I found though that I have to cache each reference, not just a reference
    > to the form, in order to get significant improvements.
    >
    > This means though that I still have one bit of code, which is used to
    > initialize the page, which is rather slow - it takes about 36 seconds
    > under Internet Explorer (and only 3 seconds under Mozilla). [...]
    >
    > <code>
    >
    > BeginBench();
    >
    > // Cache DOM values for reuse.
    > for (i=366; i >= 1; i--) {
    > c1ac = document.saisir["cal_yr1_active_jour_" + i];
    > c1ty = document.saisir["cal_yr1_type_jour_" + i];
    > c1de = document.saisir["cal_yr1_debut_jour_" + i];
    > c1fi = document.saisir["cal_yr1_fin_jour_" + i];
    > c1th = document.saisir["cal_yr1_theor_jour_" + i];
    >
    > c2ac = document.saisir["cal_yr2_active_jour_" + i];
    > c2ty = document.saisir["cal_yr2_type_jour_" + i];
    > c2de = document.saisir["cal_yr2_debut_jour_" + i];
    > c2fi = document.saisir["cal_yr2_fin_jour_" + i];
    > c2th = document.saisir["cal_yr2_theor_jour_" + i];
    > }


    IMHO this is just the wrong way of "caching". You are simply "caching"
    the DOM tree's "leaf" object's references into objects of built-in type,
    however the lookups remain (if not increased) as well as the memory usage
    does. It take it that you are trying to access a HTML form. So a
    reasonable change of the original code would be to assign a (both standards
    compliant and downwards compatible) reference to the HTMLFormElement object
    (or its `elements' collection as you can see below) to a variable and use
    that variable instead. And I sincerely doubt that you need all references
    to be "cached" in an array.

    `document.saisir' which should be `document.forms["saisir"] is accessed
    very often and you are only accessing the form's elements. So:

    // Remove redundancies and use proper references
    var es = document.forms["saisir"].elements;
    for (i=1; i <= 366; i++)
    {
    if (es["cal_yr1_type_jour_" + i].value) != 35
    || es["cal_yr1_active_jour_" + i] == 0)
    {
    es["cal_yr1_active_jour_" + i].value = 0;
    es["cal_yr1_type_jour_" + i].value = 0;
    es["cal_yr1_debut_jour_" + i].value = 0;
    es["cal_yr1_fin_jour_" + i].value = 0;
    es["cal_yr1_theor_jour_" + i].value = 0;
    }

    if (es["cal_yr2_type_jour_" + i].value != 35
    || es["cal_yr2_active_jour_" + i].value == 0)
    {
    es["cal_yr2_active_jour_" + i].value = 0;
    es["cal_yr2_type_jour_" + i].value = 0;
    es["cal_yr2_debut_jour_" + i].value = 0;
    es["cal_yr2_fin_jour_" + i].value = 0;
    es["cal_yr2_theor_jour_" + i].value = 0;
    }
    }

    // Introduce proper scoping and optimize loop
    for (var es = document.forms["saisir"].elements, i = 367;
    --i;) // 0 evaluates to `false' in a boolean expression
    {
    if (es["cal_yr1_type_jour_" + i].value) != 35
    || !es["cal_yr1_active_jour_" + i].value) // !0==true, !!0==false
    {
    es["cal_yr1_active_jour_" + i].value =
    es["cal_yr1_type_jour_" + i].value =
    es["cal_yr1_debut_jour_" + i].value =
    es["cal_yr1_fin_jour_" + i].value =
    es["cal_yr1_theor_jour_" + i].value = 0; // x=0; y=0; <=> x = y= 0;
    }

    if (es["cal_yr2_type_jour_" + i].value != 35
    || !es["cal_yr2_active_jour_" + i].value)
    {
    es["cal_yr2_active_jour_" + i].value =
    es["cal_yr2_type_jour_" + i].value =
    es["cal_yr2_debut_jour_" + i].value =
    es["cal_yr2_fin_jour_" + i].value =
    es["cal_yr2_theor_jour_" + i].value = 0;
    }
    }

    Optional optimization steps are

    for (var es = document.forms["saisir"].elements, i = 367;
    --i;) // 0 evaluates to `false' in a boolean expression
    {
    for (var j = 3; --j;)
    {
    var
    cal = "cal_yr" + j,
    cal_type_jour = cal + "_type_jour_" + i,
    cal_active_jour = cal + "_active_jour_" + i;

    if (es[cal_type_jour].value) != 35
    || !es[cal_active_jour].value) // !0==true, !!0==false
    {
    es[cal_active_jour].value =
    es[cal_type_jour].value =
    es[cal + "_debut_jour_" + i].value =
    es[cal + "_fin_jour_" + i].value =
    es[cal + "_theor_jour_" + i].value = 0; // x=0; y=0; <=> x = y= 0;
    }
    }
    }

    and so on.

    The above code is probably triggered by an event. If yes, the even listener
    should include a reference to the object that caused the event. E.g. if
    the above code is executed in a method named `setZero', it could be changed
    as follows:

    <script type="text/javascript">
    function setZero(o)
    {
    if ((o = o.form))
    {
    var e = o.elements;
    // ...
    }
    }
    }
    </script>
    ...
    <form ...>
    ...
    <script type="text/javascript">
    document.write('<input type="button" onclick="setZero(this);">');
    </script>
    ...
    </form>

    Thus the form element's name does not matter anymore and two more lookups
    per each loop are saved.

    Further optimization can be done by having the elements have the same name.
    Thus in the DOM an elements collection (an HTMLCollection object in a
    standards compliant implementation) is created which removes the need for
    concatenating the `i' value and for the hard-coded maximum index as it then
    can be obtained reading the `length' property of that collection (where
    indexes would be 0-based then). This would probably require a minor
    redesign of the server-side application, though. For server-side PHP,
    names ending with `[]' should be used as they become accessible as arrays
    instead of plain values server-side then.

    I am not sure where the `35' comes from, however this should not be
    hardcoded (at least not repeatedly) as well. This change would decrease
    performance a little bit (since it introduces a scope chain resolution
    process), but would reduce future maintenance costs.

    (And if `0' is the default value and there are no other elements (probably
    the hidden `input' elements are not required), the entire script can
    probably be replaced with <input type="reset" ...>.)

    > I need to work with the hidden "input" fields in the HTML form, as the
    > whole form is later sent to a parser which recovers everything and
    > inserts it into a database.


    It is not the parser, really.

    > I don't think it's feasible to change the design approach - too much
    > other code is involve.


    Depending on what you mean with `design approach', you may or may not
    have to accept that this will keep client-side processing slower than
    it could be.

    I wonder why you find it necessary to set the values to `0'; why do
    you not use `<input type="hidden" ... value="0">'?

    Furthermore, it appears that you do not take into account that there
    are UAs out there where client-side scripting is unavailable and so
    you have to provide a viable alternative.

    > So ... any ideas on how to reduce the initialization time of this loop,
    > or am I just stuck with it (get or take a few milliseconds)? Would
    > getting rid of the loop significantly speed things up? (I might try
    > that to see.)


    Yes, it would of course, but it would possibly also remove a feature.
    You are to decide whether that is acceptable or not, depending on the
    reply you would give to the comment right above.


    HTH

    PointedEars
    --
    Bill Gates isn't the devil -- Satan made sure hell
    _worked_ before he opened it to the damned ...
     
    Thomas 'PointedEars' Lahn, Jun 10, 2005
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    4
    Views:
    5,430
    Jonathan N. Little
    Dec 5, 2005
  2. Replies:
    8
    Views:
    534
    Jonathan N. Little
    Mar 11, 2006
  3. Paul
    Replies:
    3
    Views:
    411
  4. Ed Hauptman
    Replies:
    7
    Views:
    1,100
    Ed Hauptman
    Aug 7, 2009
  5. AC
    Replies:
    1
    Views:
    266
Loading...

Share This Page