views:

157

answers:

4

I have some javascript functions that take about 1 to 3 seconds. (some loops or mooML templating code.)

During this time, the browser is just frozen. I tried showing a "loading" animation (gif image) before starting the operation and hiding it afterwords. but it just doesnt work. The browser freezes before it could render the image and hides it immediately when the function ends.

Is there anything I can do to tell the browser to update the screen before going into javascript execution., Something like Application.DoEvents or background worker threads.

So any comments/suggestions about how to show javascript execution progress. My primary target browser is IE6, but should also work on all latest browsers

+1  A: 

Perhaps you can put in a delay between showing the animated gif and running the heavy code.

Show the gif, and call:

window.setTimeout(myFunction, 100)

Do the heavy stuff in "myFunction".

ob1
A: 

Try setting a wait cursor before you run the function, and removing it afterwards. In jQuery you can do it this way:

var body = $('body');
body.css("cursor", "wait");
lengthyProcess();
body.css("cursor", "");
Igor Zinov'yev
And without jQuery, it's even _shorter_! `document.body.style.cursor="wait"`. Magical!
Alsciende
@Alsciende, actually, it's longer. `document.body.style.cursor="wait"` against `$('body').css('cursor', 'wait')`, but I agree that one should always use the simplest method available.
Igor Zinov'yev
Actually, the jQuery solution is pretty much 70K longer...
Sean Kinsey
Depends if you were already using jQuery for something more substantial.
Piskvor
+4  A: 

This is due to everything in IE6 being executed in the same thread - even animating the gif.

The only way to ensure that the gif is displayed prior to starting is by detaching the execution.

function longRunningProcess(){
    ....

    hideGif();
}

displayGif();
window.setTimeout(longRunningProcess, 0);

But this will still render the browser frozen while longRunningProcess executes.
In order to allow interaction you will have to break your code in to smaller fragments, perhaps like this

var process = {
    steps: [
        function(){
            // step 1
            // display gif
        },
        function(){
            // step 2
        },
        function(){
            // step 3
        },
        function(){
            // step 4
            // hide gif
        }
    ],
    index: 0,
    nextStep: function(){
        this.steps[this.index++]();
        if (this.index != this.steps.length) {
            var me = this;
            window.setTimeout(function(){
                me.nextStep();
            }, 0);
        }
    }
};

process.nextStep();
Sean Kinsey
awesome...cool fix. Thank you
novice
A: 

You have to use a little more sophisticated technique to show the progress of the long running function.

Let's say you have a function like this that runs long enough:

function longLoop() {
    for (var i = 0; i < 100; i++) {
        // Here the actual "long" code
    }
}

To keep the interface responsive and to show progress (also to avoid "script is taking too long..." messages in some browsers) you have to split the execution into the several parts.

function longLoop() {
    // We get the loopStart variable from the _function_ instance. 
    // arguments.callee - a reference to function longLoop in this scope
    var loopStart = arguments.callee.start || 0;

    // Then we're not doing the whole loop, but only 10% of it
    // note that we're not starting from 0, but from the point where we finished last
    for (var i = loopStart; i < loopStart + 10; i++) {
        // Here the actual "long" code
    }

    // Next time we'll start from the next index
    var next = arguments.callee.start = loopStart + 10;
    if (next < 100) {

        updateProgress(next); // Draw progress bar, whatever.
        setTimeout(arguments.callee, 10);
    }
}

I haven't tested this actual code, but I have used this technique before.

Juriy