Javascript: Non-blocking way to wait until a condition is true

39,314

Solution 1

There is no such functionality such as wait or sleep in javascript, since it would stop browser from responding.

In your case I would go with something similar to following:

function wait(){
  if (!condition){
    setTimeout(wait,100);
  } else {
    // CODE GOES IN HERE
  }
}

Solution 2

It's easy to make a mistake when calling setTimeout that will cause the JavaScript call stack to fill up. If your function has parameters, you need to pass those in at the end of the setTimeout parameter list like this:

function wait(param1, param2){
  if (!condition){
    setTimeout(wait, 100, param1, param2);
  } else {
    // CODE GOES IN HERE
  }
}

If you pass parameters or even include empty () after the name of the function, it will be executed immediately and fill up the stack.

// This is the wrong way to do it!    
function wait(param1, param2){
  if (!condition){
    setTimeout(wait(param1, param2), 100); // you'll get max call stack error if you do this!
  } else {
    // CODE GOES IN HERE
  }
}

Solution 3

I needed to slow down a process and came up with a helpful little method.

wait = (seconds) => 
   new Promise(resolve => 
      setTimeout(() => resolve(true), seconds * 1000)
   );

And you can use it like this.

doWork = async() => {
   if(await this.wait(3)) {
       // After 3 seconds do something...
   }
}

Solution 4

This function calls condFunc which should return true when condition is met. When that happens readyFunc is called. checkInterval sets checking rate in milliseconds

       var wait = function(condFunc, readyFunc, checkInterval) {
            var checkFunc = function() {
                if(condFunc()) {
                    readyFunc(); 
                }
                else
                {
                    setTimeout(checkFunc, checkInterval);
                }
            };
            checkFunc();
        };

Usage:

       wait(
            function() { return new Date().getSeconds() == 10; }, 
            function() { console.log("Done"); },
            100
        );

prints "Done" when current time is 10 seconds after minute

Share:
39,314
oscilatingcretin
Author by

oscilatingcretin

pronouns: you/your

Updated on December 03, 2020

Comments

  • oscilatingcretin
    oscilatingcretin over 3 years

    I have several ASP.NET UpdatePanels, each with an AsyncPostBackTrigger tied to the same button's serverside click event. Since only one UpdatePanel can be doing its thing at a time, I use .get_isInAsyncPostBack() of the PageRequestManager to prevent a user from being able to access another part of the page until the async postback is complete.

    Another part of this page needs to dynamically update multiple update panels consecutively. Since the update panels use async triggers, calling __doPostBack("<%=ButtonName.ClientID %>", 'PanelId'); fires asynchonously. Because of this, it will quickly move along to the next iteration of the loop and try to update the next panel. However, the second iteration fails because there is already another update panel doing an async postback.

    Ideally, there would be a way to wait until .get_isInAsyncPostBack() returns false without blocking other client activity.

    Research has lead me to a lot people with my problem, almost all of whom are advised to use setTimeOut(). I do not thing this will work for me. I don't want to wait for a specified amount of time before executing a function. I simply want my Javascript to wait while another script is running, preferably wait until a specific condition is true.

    I understand that many will probably want to suggest that I rethink my model. It's actually not my model, but one that was handed to our development team that is currently a total mess under the hood. Due to time contraints, rewriting the model is not an option. The only option is to make this work. I think that if I had a way to make the client code wait without blocking, my problem would be solved.

    • user2428118
      user2428118 over 11 years
      That's simply not how JavaScript works. It will execute all code synchronously. HTML5s cool new Web Workers might help, but for the rest you'll have no choice but to use setTimeout / setInterval.
    • pylover
      pylover over 10 years
      Good question.i found it when i trying two write one.
    • Xesenix
      Xesenix almost 5 years
      Currently, maybe a better way of solving such issues would be to use web worker for waiting for server-side answer.
  • oscilatingcretin
    oscilatingcretin over 11 years
    I am not sure how this is supposed to work. When I execute this code setTimeout(function () { alert("waiting"); }, 5000); alert("donewaiting");, "donewaiting" is alerted first, followed by "waiting" 5 second later. What's the point of waiting if it's just going to move immediately to the next line of code?
  • Marian Bazalik
    Marian Bazalik over 11 years
    the concept of set timeout is different, it does not stop the execution of code, but executes code after some time. There is NO WAY (at least good) of pausing the script. You will have to replace ... CODE GOES IN HERE ... with the logic should be executed after the condition is met
  • Heretic Monkey
    Heretic Monkey over 11 years
    This 'polling' technique essentially runs the wait function every 100 ms until the condition becomes true. For your purposes, I would replace condition here with .get_isInAsyncPostBack() and ...CODE GOES IN HERE... with the call to update the next panel, followed by a wait for the next panel. You'll want a new wait() function for each panel (e.g., waitForPanel1(), waitForPanel2(), etc.
  • pylover
    pylover over 10 years
    How about javascript maximum call-stack size?
  • CoderDennis
    CoderDennis over 10 years
    @pylover using setTimeout should not affect the call-stack because it doesn't execute the function again until after the current function has completed. It is possible to do it wrong. I'll add an answer to cover that.
  • Guilherme Orioli
    Guilherme Orioli over 4 years
    This is a non blocking way to wait without the need of a recursive call. I like it.