Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I allow a webpage to update while a javascript is running?

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;
    };
    };
};
like image 666
Andrew Dabrowski Avatar asked Sep 06 '25 03:09

Andrew Dabrowski


2 Answers

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

like image 73
Drew Avatar answered Sep 07 '25 20:09

Drew


If you only need to support modern browsers (or if you use a transpiler), you can now use ES6 features to make this much easier and more in the style the original questioner was trying to do. (I realize the question is 8 years old - no harm in a new, more current answer!)

For example you can do something like this:

// helper function to use a setTimeout as a promise.
function allowUpdate() {
  return new Promise((f) => {
    setTimeout(f, 0);
  });
}

// An infinitely looping operation that doesn't crash the browser.
async function neverStopUpdating(someElement) {
  let i = 0;
  while (true) {
    someElement.innerText = i;
    i++;
    await allowUpdate();
  }
}

If you're trying to do a hard computation you'll want to make sure not to do this await too frequently - in this example, in Chrome at time of writing, i only increments by about 150 per second because the context switch of a setTimeout is not fast (where you'd get hundreds of thousands in a second if you didn't yield for updates). You'd likely want to find a balance, either always perform some number of iterations before allowing an update, or maybe eg. call Date.now() in your loop and yield for an update whenever 100ms have passed since the last time you allowed an update.

like image 28
Raven Black Avatar answered Sep 07 '25 21:09

Raven Black