views:

42

answers:

3

There has to be an easy way to do this, but I'm new to JS.

I have a javascript program that (1) takes user input, (2) updates the webpage based on that input, then (3) performs a lengthy calculation. The trouble is that the webpage doesn't register the update till after the lengthy calculation. Isn't there a way to pause execution so that the page can update before the long calculation?

I've tried setTimeout and window.setTimeout, but they made no difference.

The program is for playing a game: the user inputs a move, the script updates the position, then calculates its next move. postMessage prints text messages using div.innerHTML; buttonFn takes the input from the user, updates the position, prints a message, then starts the computer calculating.

function buttonFn(arg){
    var hst = histButt;
    hst.push(arg);
    var nwmv = hst.clone();

    postMessage("New move: " + nwmv.join());
    if(status == opposite(comp) && !pauseQ){
    var mvsposs = movesFromPos(posCur,status);
    if(mvsposs.has(nwmv)){
        updatePosCur(nwmv);
        //waitasec();
        if(comp == status && !pauseQ){
        compTurn();
        };
    }
    else{
        histButt = nwmv;
    };
    };
};
A: 

You can do the update, wait for a bit of time, than do the calculation.

OR

You can use webworkers on browsers that support them.

Without having actual code, that is the best answer that I can give you.

epascarello
Never heard of webworkers, I'll check that out, thanks. How do I "wait a bit of time"? I thought that's what setTimeout was supposed to do.
Andrew Dabrowski
@Andrew, well if setTimeout is not working, sounds like you are not allowing for enough time for the redraw to happen.
epascarello
I've tried giving it as much as 5 seconds, shouldn't that be enough?
Andrew Dabrowski
A: 

JavaScript is single threaded. If you do your calc server side you could get the results via ajax which is called asynchronously, not blocking your ui.

jms
Because the computations can be lengthy I thought it more appropriate to have the client do them.
Andrew Dabrowski
+2  A: 

yes there is, call your function like this. Using setTimeout will allow a page reflow prior to your JS executing.

function buttonFn(arg){
    var hst = histButt;
    hst.push(arg);
    var nwmv = hst.clone();

    postMessage("New move: " + nwmv.join());
    if(status == opposite(comp) && !pauseQ){
    var mvsposs = movesFromPos(posCur,status);
    if(mvsposs.has(nwmv)){
        updatePosCur(nwmv);
        //waitasec();

        if(comp == status && !pauseQ){
        setTimeout(function(){
          compTurn();
        },0);

        };
    }
    else{
        histButt = nwmv;
    };
    };
};

Remember, JS is very event driven friendly. If you can move things off, and call them later do it. Thats the only way we can support multi-threaded like behavior.

setTimeout

Drew
What does the parameter of 0 ms mean?
Andrew Dabrowski
It tells the JS engine to delay execution. By putting your long running function in a function closure as so, JS will execute the remaining part of buttonFn then execute whatever is inside the setTimeout. If there is a browser reflow (DOM changed), this will occur as well before compTurn runs
Drew
Thanks! That worked! But why is it necessary to wrap compTurn() in a function construct? And why 0ms rather than say, 100ms?
Andrew Dabrowski
You can put whatever you want, but I don't think you want compTurn to run later. You just want the application to be responsive. setTimeout executes the function passed to it after a so many milliseconds, in this case 0ms. If you just put setTimeout above your compTurn(), it will execute nothing after 0ms and continue running the rest of your code in procedural fashion.
Drew
Thanks a lot! I think my mistake was just using setTimeout(compTurn(),100), I didn't realize the expression has to be wrapped. Quoting it seems to work also.
Andrew Dabrowski
@Andrew `setTimeout(compTurn())` first *executes* `compTurn()`, then passes the result of that function to `setTimeout()`. Use an anonymous function wrap like Drew demonstrates or just *pass* the function like `setTimeout(compTurn)` *without executing it* (no `()`). `setTimeout('compTurn()')` works too, but differently and not in all situations.
deceze
OK, I think I've got it. Thanks to everyone!
Andrew Dabrowski
Don't worry, it took me a while to figure out the screwy behavior of setTimeout. It is a pretty crappy function to be honest.
Drew