Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can I do to optimize my ajax application for IE7/IE8 in order to avoid "Stop running this script"?

I have a booking engine which is pretty sluggish in IE7. It's ajaxified and hash/window onchange based. There are 5 total steps. The main issue I'm having is step 2 is uber slow in IE.

When a user lands on step 2, an ajax request is made to pull in data with web services in order to display hotel rooms. The hotel rooms are divided by the main room type and more specific types inside. The JS functionality that gets applied to the hotel rooms consist of:

  • accordion on the rooms
  • accordion on the room types (nested accordion)
  • quickflip on the image
  • jscrollpane, custom scrollbar on the room description on the left after the image flips
  • jscrollpane, custom scrollbar on the room types on the right

All of this causes the famous:

enter image description here

I've googled and landed on this, this, and this.

So obviously the cause is that there are too many script statements executing sequentially within a specific amount of time in IE.

I basically need to refactor my code and optimize it such that there are delays in between function invocations.

The way I'm injecting the HTML after doing the ajax request is:

 734                     $( o.html ).appendTo( el )

o.html is a reference to the JSON objects html property which is derived from here.

Then, the code below runs:

setTimeout(function () {


    $('#roomz .room-accordion').each(function () {

        $(this).accordion({
            header: 'h2.new-heading',
            autoheight: false,
            clearStyle: true,
            collapsible: true,
            change: function (event, ui) {
                window.ui = ui;

                // if it hasnt been quickflipped/subnest accordioned, do it
                if (!$(ui.newContent).data('enabled')) {
                    $('.room-rates', ui.newContent).each(function () {

                        $(this).accordion({
                            header: 'h4.rate-name',
                            autoheight: false,
                            active: 0,
                            clearStyle: true
                        });

                        //if (!$.browser.msie) 
                           $(this).jScrollPane();

                    })

                    $('.room-image', ui.newContent).quickFlip({
                        vvertical: true
                        //easing:'easeInBounce'
                        //easing:'easeInSine'
                    });

                    $('.back-copy-inner', ui.newContent).jScrollPane({
                        verticalDragMaxHeight: 131
                    });

                    $(ui.newContent).data('enabled', true);
                }
            }
        })

        var el = this;
        setTimeout(function () {
            $('.back-copy-inner:eq(0)', el).jScrollPane({
                verticalDragMaxHeight: 131
            });
        }, 500);

        $('.room-rates:eq(0)', this).each(function () {

            $(this).accordion({
                header: 'h4.rate-name',
                autoheight: false,
                active: 0,
                clearStyle: true
            });

            var el = this;
            setTimeout(function () {
                //if (!$.browser.msie) 
                $(el).jScrollPane();
            }, 50);

        });

        $('.room-image:eq(0)', this).quickFlip({
            vvertical: true
            //easing:'easeInBounce'
            //easing:'easeInSine'
        });

        $('.room:eq(0)', this).data('enabled', true);

    });



}, 20);

My first version of the code basically applied the quickflip and scrollpanes to every room whether it was hidden in the accordion or not. The refactored version ( live/current one ) applies it to the very first room that's active in the accordion, and when another is clicked on through the accordion, I apply the quickflip and scrollpane to it.

I added a setTimeout around the entire thing, because this happens after the HTML gets injected. I have setTimeouts inside as well.

It seems like it's still too slow. Can anyone offer any refactoring/optimization tips?

My ideas for refactoring it again consist of:

  1. instead of doing an .each on .room accordion, apply a repeating operation to force a delay in between each iteration like this?
  2. optimize and minify the HTML returned by the ajax even more - I have already done lots of optimization, killed whitespace, dont show HTML comments, etc..
  3. Enabling Gzip
  4. Doing lazy loading on the images so that only the visible accordion content images show and others are blank.gif until you activate them through the accordion
  5. Instead of returning the HTML and dumping it, return only relevant data with NO HTML and instead build the HTML with a templating engine?!

If anyone can offer opinions on my ideas for refactoring in terms of which ones would produce the best results, that'd be great too.

LINKS:

  • the page in question is this.
  • the relevant JS is here.
  • the relevant code/line numbers start at line 829 of new.js ( thats the snippet I pasted )
  • the relevant ajax request that is made is made to this page.

PS - not supporting IE6

EDIT: I put a delay between iteration of .each and it's still uber slow. I think the custom scrollbar is the leading cause. Ugh.

EDIT #2: The live code is a spaghetti of setTimeouts. I tried to lazy load the scroll pane but its still too sluggish for IE.

like image 410
meder omuraliev Avatar asked May 15 '11 04:05

meder omuraliev


1 Answers

To make the IE script is too slow message dissapear you need to use more setTimeout. The problem is hitting 5 million javascript commands. setTimeout resets this counter.

Replacing the accordion calls

$(this).accordion({
    ...
});

With

var that = this;
setTimeout(function() {
    $(that).accordion({ ... });
}, 0);

Should fix your problem. It won't speed up the code though, it will just make the script is too slow dissapear.

As for actual optimisation there are two obvouis things.

Instead of $('.room:eq(0)')

Use $(".room").eq(0)

Edit

.each(function() {
    setTimeout(function() {
        ...
    }, 0);
}
like image 128
Raynos Avatar answered Nov 03 '22 09:11

Raynos