Wait until flag=true

JavascriptSynchronization

Javascript Problem Overview


I have javascript function like this:

function myFunction(number) {

    var x=number;
    ...
    ... more initializations
    //here need to wait until flag==true
    while(flag==false)
    {}

    ...
    ... do something

}

The problem is that the javascript is stuck in the while and stuck my program. so my question is how can I wait in the middle of the function until flag is true without "busy-wait"?

Javascript Solutions


Solution 1 - Javascript

Javascript is single threaded, hence the page blocking behaviour. You can use the deferred/promise approach suggested by others. The most basic way would be to use window.setTimeout. E.g.

function checkFlag() {
    if(flag === false) {
       window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/
    } else {
      /* do something*/
    }
}
checkFlag();

Here is a good tutorial with further explanation: Tutorial

EDIT

As others pointed out, the best way would be to re-structure your code to use callbacks. However, this answer should give you an idea how you can 'simulate' an asynchronous behaviour with window.setTimeout.

Solution 2 - Javascript

Because javascript in a browser is single threaded (except for webworkers which aren't involved here) and one thread of javascript execution runs to completion before another can run, your statement:

while(flag==false) {}

will simply run forever (or until the browser complains about a non-responsive javascript loop), the page will appear to be hung and no other javascript will ever get a chance to run, thus the flag's value can never be changed.

For a little more explanation, Javascript is an event driven language. That means that it runs a piece of Javascript until it returns control back to the interpreter. Then, only when it returns back to the interpreter, Javascript gets the next event from the event queue and runs it.

All things like timers and network events run through the event queue. So, when a timer fires or a network request arrives, it does not ever "interrupt" the currently running Javascript. Instead, an event gets put in the Javascript event queue and then, when the currently running Javascript finishes, the next event is pulled from the event queue and it gets its turn to run.

So, when you do an infinite loop such as while(flag==false) {}, the currently running Javascript never finishes and thus the next event is never pulled from the event queue and thus the value of flag never gets changed. They key here is that Javascript is not interrupt driven. When a timer fires, it does not interrupt the currently running Javascript, run some other Javascript and then let the currently running Javascript continue. It just gets put in the event queue waiting until the currently running Javascript is done to get its turn to run.


What you need to do is rethink how your code works and find a different way to trigger whatever code you want to run when the flag value changes. Javascript is designed as an event-driven language. So, what you need to do is figure out what events you can register an interest in so you can either listen for the event that might cause the flag to change and you can examine the flag on that event or you can trigger your own event from whatever code might change the flag or you can implement a callback function that whatever code changes that flag can call your callback whenever the piece of code responsible for changing the flag value would change it's value to true, it just calls the callback function and thus your code that wants to run when the flag gets set to true will get to run at the right time. This is much, much more efficient than trying to use some sort of timer to constantly check the flag value.

function codeThatMightChangeFlag(callback) {
    // do a bunch of stuff
    if (condition happens to change flag value) {
        // call the callback to notify other code
        callback();
    }
}

Solution 3 - Javascript

Solution using Promise, async\await and EventEmitter which allows to react immediate on flag change without any kind of loops at all

const EventEmitter = require('events');

const bus = new EventEmitter();
let lock = false;

async function lockable() {
    if (lock) await new Promise(resolve => bus.once('unlocked', resolve));
    ....
    lock = true;
    ...some logic....
    lock = false;
    bus.emit('unlocked');
}

EventEmitter is builtin in node. In browser you shall need to include it by your own, for example using this package: https://www.npmjs.com/package/eventemitter3

Solution 4 - Javascript

ES6 with Async / Await ,

let meaningOfLife = false;
async function waitForMeaningOfLife(){
   while (true){
        if (meaningOfLife) { console.log(42); return };
        await null; // prevents app from hanging
   }
}
waitForMeaningOfLife();
setTimeout(()=>meaningOfLife=true,420)

Solution 5 - Javascript

function waitFor(condition, callback) {
    if(!condition()) {
        console.log('waiting');
        window.setTimeout(waitFor.bind(null, condition, callback), 100); /* this checks the flag every 100 milliseconds*/
    } else {
        console.log('done');
        callback();
    }
}

Use:

waitFor(() => window.waitForMe, () => console.log('got you'))

Solution 6 - Javascript

Modern solution using Promise

myFunction() in the original question can be modified as follows

async function myFunction(number) {

    var x=number;
    ...
    ... more initializations

    await until(_ => flag == true);

    ...
    ... do something

}

where until() is this utility function

function until(conditionFunction) {

  const poll = resolve => {
    if(conditionFunction()) resolve();
    else setTimeout(_ => poll(resolve), 400);
  }

  return new Promise(poll);
}

Some references to async/await and arrow functions are in a similar post: https://stackoverflow.com/a/52652681/209794

Solution 7 - Javascript

With Ecma Script 2017 You can use async-await and while together to do that And while will not crash or lock the program even variable never be true

//First define some delay function which is called from async function
function __delay__(timer) {
    return new Promise(resolve => {
        timer = timer || 2000;
        setTimeout(function () {
            resolve();
        }, timer);
    });
};

//Then Declare Some Variable Global or In Scope
//Depends on you
var flag = false;

//And define what ever you want with async fuction
async function some() {
    while (!flag)
        await __delay__(1000);

    //...code here because when Variable = true this function will
};

Solution 8 - Javascript

I solved this issue by implementing the method below.

const waitUntil = (condition) => {
    return new Promise((resolve) => {
        let interval = setInterval(() => {
            if (!condition()) {
                return
            }

            clearInterval(interval)
            resolve()
        }, 100)
    })
}

Now, whenever you want to wait until a certain condition is met you can call it like this.

await waitUntil(() => /* your condition */)

Solution 9 - Javascript

For iterating over ($.each) objects and executing a longish-running operation (containing nested ajax sync calls) on each object:

I first set a custom done=false property on each.

Then, in a recursive function, set each done=true and continued using setTimeout. (It's an operation meant to stop all other UI, show a progress bar and block all other use so I forgave myself for the sync calls.)

function start()
{
    GlobalProducts = getproductsfromsomewhere();
    $.each(GlobalProducts, function(index, product) {
         product["done"] = false;
    });

    DoProducts();
}
function DoProducts()
{
    var doneProducts = Enumerable.From(GlobalProducts).Where("$.done == true").ToArray(); //linqjs

    //update progress bar here

    var nextProduct = Enumerable.From(GlobalProducts).Where("$.done == false").First();

        if (nextProduct) {
            nextProduct.done = true;
            Me.UploadProduct(nextProduct.id); //does the long-running work

            setTimeout(Me.UpdateProducts, 500)
        }
}

Solution 10 - Javascript

If you are allowed to use: async/await on your code, you can try this one:

const waitFor = async (condFunc: () => boolean) => {
  return new Promise((resolve) => {
    if (condFunc()) {
      resolve();
    }
    else {
      setTimeout(async () => {
        await waitFor(condFunc);
        resolve();
      }, 100);
    }
  });
};

const myFunc = async () => {
  await waitFor(() => (window as any).goahead === true);
  console.log('hello world');
};

myFunc();

Demo here: https://stackblitz.com/edit/typescript-bgtnhj?file=index.ts

On the console, just copy/paste: goahead = true.

Solution 11 - Javascript

The cleanest solution (improvement of @tdxius solution) based on controlled time interval loop, promise and timeout to reject the promise and clear intervals in case condition isn't met in a given time

const waitUntil = (condition) => {
                    return new Promise((resolve, reject) => {
                        const interval = setInterval(() => {
                            if (!condition()) {
                                return;
                            }

                            clearInterval(interval);
                            resolve();
                        }, 100);

                        setTimeout(() => {
                            clearInterval(interval);
                            reject('your error msg');
                        }, 5000);
                    });
                };

Now, whenever you want to wait until a certain condition is met, you can call it like this.

waitUntil(CONDITION_FUNCTION)
  .then(() => DO_SOMETHING)
  .catch((YOUR_ERROR_MSG) => console.warn(YOUR_ERROR_MSG))

Solution 12 - Javascript

Similar to Lightbeard's answer, I use the following approach

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

async function until(fn) {
    while (!fn()) {
        await sleep(0)
    }
}

async function myFunction(number) {
    let x = number
    ...
    ... more initialization
    
    await until(() => flag == true)

    ...
    ... do something
}

Solution 13 - Javascript

I tried to used @Kiran approach like follow:

checkFlag: function() {
  var currentObject = this; 
  if(flag == false) {
      setTimeout(currentObject.checkFlag, 100); 
   } else {
     /* do something*/
   }
}

(framework that I am using force me to define functions this way). But without success because when execution come inside checkFlag function second time, this is not my object it is Window. So, I finished with code below

checkFlag: function() {
    var worker = setInterval (function(){
         if(flag == true){             
             /* do something*/
              clearInterval (worker);
         } 
    },100);
 }

Solution 14 - Javascript

using non blocking javascript with EventTarget API

In my example, i need to wait for a callback before to use it. I have no idea when this callback is set. It can be before of after i need to execute it. And i can need to call it several time (everything async)

// bus to pass event
const bus = new EventTarget();

// it's magic
const waitForCallback = new Promise((resolve, reject) => {
    bus.addEventListener("initialized", (event) => {
        resolve(event.detail);
    });
});



// LET'S TEST IT !


// launch before callback has been set
waitForCallback.then((callback) => {
    console.log(callback("world"));
});


// async init
setTimeout(() => {
    const callback = (param) => { return `hello ${param.toString()}`; }
    bus.dispatchEvent(new CustomEvent("initialized", {detail: callback}));
}, 500);


// launch after callback has been set
setTimeout(() => {
    waitForCallback.then((callback) => {
        console.log(callback("my little pony"));
    });
}, 1000);

Solution 15 - Javascript

there is a node package delay very easy to use

const delay = require('delay');

(async () => {
    bar();
 
    await delay(100);
 
    // Executed 100 milliseconds later
    baz();
})();

Solution 16 - Javascript

I took an approach along the lines of the callback solutions here, but tried to make it a bit more generic. The idea is you add functions that you need to execute after something changes to a queue. When the thing happens, you then loop through the queue, call the functions and empty the queue.

Add function to queue:

let _queue = [];

const _addToQueue = (funcToQ) => {
    _queue.push(funcToQ);
}

Execute and flush the queue:

const _runQueue = () => {
    if (!_queue || !_queue.length) {
        return;
    }

    _queue.forEach(queuedFunc => {
        queuedFunc();
    });

    _queue = [];
}

And when you invoke _addToQueue you'll want to wrap the callback:

_addToQueue(() => methodYouWantToCallLater(<pass any args here like you normally would>));

When you've met the condition, call _runQueue()

This was useful for me because I had several things that needed to wait on the same condition. And it decouples the detection of the condition from whatever needs to be executed when that condition is hit.

Solution 17 - Javascript

Try avoid while loop as it could be blocking your code, use async and promises.

Just wrote this library:

https://www.npmjs.com/package/utilzed

There is a function waitForTrue

import utilzed from 'utilzed'

const checkCondition = async () => {
  // anything that you are polling for to be expecting to be true
  const response = await callSomeExternalApi();
  return response.success;
}

// this will waitForTrue checkCondition to be true
// checkCondition will be called every 100ms
const success = await utilzed.waitForTrue(100, checkCondition, 1000);

if (success) {
  // Meaning checkCondition function returns true before 1000 ms
  return;
}

// meaning after 1000ms the checkCondition returns false still
// handle unsuccessful "poll for true" 

Solution 18 - Javascript

Did anyone ever think of just doing this?

function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, 2000);
  });
}




function myFunction(number) {

    var x=number;
    ...
    ... more initializations
    //here need to wait until flag==true
    while(flag==false)
    {
         await resolveAfter2Seconds();
    }

    ...
    ... do something

}

Solution 19 - Javascript

//function a(callback){
setTimeout(function() {
  console.log('Hi I am order 1');
}, 3000);
 // callback();
//}

//function b(callback){
setTimeout(function() {
  console.log('Hi I am order 2');
}, 2000);
//   callback();
//}



//function c(callback){
setTimeout(function() {
  console.log('Hi I am order 3');
}, 1000);
//   callback();

//}

 
/*function d(callback){
  a(function(){
    b(function(){
      
      c(callback);
      
    });
    
  });
  
  
}
d();*/


async function funa(){
  
  var pr1=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 1"),3000)
        
  })
  
  
   var pr2=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 2"),2000)
        
  })
   
    var pr3=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 3"),1000)
        
  })

              
  var res1 = await pr1;
  var res2 = await pr2;
  var res3 = await pr3;
  console.log(res1,res2,res3);
  console.log(res1);
   console.log(res2);
   console.log(res3);

}   
    funa();
              


async function f1(){
  
  await new Promise(r=>setTimeout(r,3000))
    .then(()=>console.log('Hi3 I am order 1'))
    return 1;                        

}

async function f2(){
  
  await new Promise(r=>setTimeout(r,2000))
    .then(()=>console.log('Hi3 I am order 2'))
         return 2;                   

}

async function f3(){
  
  await new Promise(r=>setTimeout(r,1000))
    .then(()=>console.log('Hi3 I am order 3'))
        return 3;                    

}

async function finaloutput2(arr){
  
  return await Promise.all([f3(),f2(),f1()]);
}

//f1().then(f2().then(f3()));
//f3().then(f2().then(f1()));
  
//finaloutput2();

//var pr1=new Promise(f3)







async function f(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 1');
}, 3000);
  });
    
  
  var result=await pr;
  console.log(result);
}

 // f(); 

async function g(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 2');
}, 2000);
  });
    
  
  var result=await pr;
  console.log(result);
}
  
// g(); 

async function h(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 3');
}, 1000);
  });
    
  
  var result=await pr;
  console.log(result);
}

async function finaloutput(arr){
  
  return await Promise.all([f(),g(),h()]);
}
  
//finaloutput();

 //h(); 
  
  
  
  
  
  

Solution 20 - Javascript

In my example, I log a new counter value every second:

var promises_arr = [];
var new_cntr_val = 0;

// fill array with promises
for (let seconds = 1; seconds < 10; seconds++) {
    new_cntr_val = new_cntr_val + 5;    // count to 50
    promises_arr.push(new Promise(function (resolve, reject) {
        // create two timeouts: one to work and one to resolve the promise
        setTimeout(function(cntr) {
            console.log(cntr);
        }, seconds * 1000, new_cntr_val);    // feed setTimeout the counter parameter
        setTimeout(resolve, seconds * 1000);
    }));
}

// wait for promises to finish
Promise.all(promises_arr).then(function (values) {
    console.log("all promises have returned");
});

Solution 21 - Javascript

Inspired by jfriend00, this worked for me

const seconds = new Date();
// wait 5 seconds for flag to become true
const waitTime = 5
const extraSeconds = seconds.setSeconds(seconds.getSeconds() + waitTime);
while (Date.now() < extraSeconds) {
  // break when flag is false
  if (flag === false) break;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionilay zeidmanView Question on Stackoverflow
Solution 1 - JavascriptKiranView Answer on Stackoverflow
Solution 2 - Javascriptjfriend00View Answer on Stackoverflow
Solution 3 - JavascriptYaroslav DobzhanskijView Answer on Stackoverflow
Solution 4 - JavascriptCode WhispererView Answer on Stackoverflow
Solution 5 - JavascriptMaciej DudziƄskiView Answer on Stackoverflow
Solution 6 - JavascriptLightbeardView Answer on Stackoverflow
Solution 7 - JavascriptToprakView Answer on Stackoverflow
Solution 8 - JavascripttdxiusView Answer on Stackoverflow
Solution 9 - JavascriptRodneyView Answer on Stackoverflow
Solution 10 - JavascriptViewsonicView Answer on Stackoverflow
Solution 11 - JavascriptEranGrinView Answer on Stackoverflow
Solution 12 - JavascriptChris_FView Answer on Stackoverflow
Solution 13 - JavascriptyurinView Answer on Stackoverflow
Solution 14 - JavascriptMelvbobView Answer on Stackoverflow
Solution 15 - JavascriptEricView Answer on Stackoverflow
Solution 16 - JavascriptfigelwumpView Answer on Stackoverflow
Solution 17 - JavascriptWilson LimView Answer on Stackoverflow
Solution 18 - JavascriptJeff MorettiView Answer on Stackoverflow
Solution 19 - JavascriptAvinash MauryaView Answer on Stackoverflow
Solution 20 - JavascriptxinthoseView Answer on Stackoverflow
Solution 21 - JavascriptunangityView Answer on Stackoverflow