0

I've got a long running method -- and I want to indicate to the user that an operation is underway. This is NOT and ajax call, so I can't use the common pattern I've used in the past to display, say a spinner, before the ajax event, then hiding it on success for example.

In my case -- I'm not making an ajax call, I'm instead doing some very heavy DOM manipulation.

I had a test example on jsFiddle.net -- would love to learn how to capture the event. At the moment, my "wait-message" div updates at the same exact time when my operation completes which is much too late :(

Complete sample code is here: http://jsfiddle.net/rsturim/97hrs/6/

Javascript (jQuery)

$(document).ready(function() {

    $("#link-action").click(function(e) {

        $("#wait-message").text("starting ...");

        var count = longRunningMethod(1000000000);

        $("#result").text(count);
        $("#wait-message").text("completed.");

    });


    var longRunningMethod = function(countUpTo) {
        var i = 0;
        while (i <= countUpTo) {

            i++;
        }

        return i;

    };
});

HTML:

<div id="wait-message">
    push button please 
</div>   
<hr />

<button id="link-action">Run Operation</button>

<hr />

<h1>Results:</h1>
<div id="result"> </div>   
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
rsturim
  • 6,756
  • 15
  • 47
  • 59
  • duplicate: http://stackoverflow.com/questions/7342084/jquery-javascipt-how-to-wait-for-manipulated-dom-to-update-before-proceeding-w – ampersand Dec 15 '11 at 22:57

2 Answers2

1

Here is a solution. I'm not sure if it works in all browsers, you may want to test it out in several, but I think it does:

$(document).ready(function() {

    $("#link-action").click(function(e) {

        $("#wait-message").text("starting ...");

        // Stuff to do after a render
        setTimeout(function(){
            var count = longRunningMethod(1000000000);

            $("#result").text(count);
            $("#wait-message").text("completed.");
        }, 0);
    });


    var longRunningMethod = function(countUpTo) {
        var i = 0;
        while (i <= countUpTo) {

            i++;
        }

        return i;

    };
});

Basically, the browser won't render any changes until a script finishes executing. That allows you to do things like:

  • Hide all divs with a certain class
  • Show one of those divs

In a row and the browser will never render the div that is being shown as hidden, so you won't get weird flickers or things moving around on the page.

Using setTimeout like I did, the anonymous click handler will finish executing, the browser will re-render, the the anonymous function in the setTimeout will run (immediately after the render since there is no actual delay).

Paul
  • 139,544
  • 27
  • 275
  • 264
  • Doesn't make a difference for me running FF8. – lonesomeday Dec 15 '11 at 22:40
  • @lonesomeday It works for me in Chrome IE. it says "starting..." in the div for a little bit before changing to "completed.". http://jsfiddle.net/97hrs/7/ I'm not sure, but maybe changing the 0 to a 1 would make it work in FF? – Paul Dec 15 '11 at 22:44
  • @lonesomeday I don't have Firefox to test it myself. – Paul Dec 15 '11 at 22:44
0

Use setTimeout or setInterval instead of your while loop; a sub-second delay like 15ms should be enough to prevent your window freezing / UI locking.

Graham
  • 6,484
  • 2
  • 35
  • 39