How to wait until a predicate condition becomes true in JavaScript?
Asked Answered
L

25

153

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"?

Lafave answered 2/3, 2014 at 9:22 Comment(5)
Use the promise pattern for your initializations - can be found in quite some libraries like jQuery.Deferred, Q, async, ...Gillman
where exactly to use it and how?Lafave
There are plenty of tutorials around describing the promise implementations of the various libraries, eg. jQuery.Deferred or Q. Btw, your underlying problem is the same as in this question.Gillman
For someone reading this in 2018, Promises are supported by all browsers besides opera mini and IE11.Quinacrine
The main problem is that it is impossible to do truly blocking (sleep) wait in event-diven single-threaded js. You can only create wait handler. see more: #41842647Ornstead
W
95

You created an infinite loop where the flag value that terminates the loop can never be changed by code outside this loop because no code outside the loop ever gets to run - thus this will never work.

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:

// this won't work!
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 by code outside this loop.

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();
    }
}
Windhoek answered 2/3, 2014 at 9:36 Comment(2)
this is misleading that while(flag==false) {} is the answer at first glance...Phrenetic
@Phrenetic - Fair enough. I edited the first couple paragraphs.Windhoek
W
149

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.

Wommera answered 2/3, 2014 at 9:28 Comment(8)
While on the one hand I really like this answer because it is indeed a js 'wait' it becomes not so usable if you would like to return a value. If you do not return a value I am not so sure there is a real world usecase for the pattern?Nairn
You can of course return a promise and implement the function in that way. However this would generally require a third party library that implements promises or polyfill, unless you're using ECMA-262. Without returning a promise, the best way is to use a callback mechanism to signal to the caller that a result is available.Wommera
You can also pass parameters if required: #1191142Inferno
This is such a great answer. I was almost giving up after digging thru many tech forums. I think it perfectly worked for me because I was returning a value. It also worked on Internet Explorer too.Thanks a bunch.Blanchard
If for any reason we need to send parameters to checkFlag function then we have to use anonymous/arrow function like, window.setTimeout( () => { checkFlag(params); }, 100);Briseno
Such a cool design. Can also add a timeout to it as well ;)Pew
Is that synchronous?Mocambique
In my case I implemented it in my function directly and had to pass a parameter so JS would return "InternalError: too much recursion" but it worked using an anonymous function inside the setTimeout instead of the call to itself directly: setTimeout(() => { createNewLine(text) }, time);Guertin
W
95

You created an infinite loop where the flag value that terminates the loop can never be changed by code outside this loop because no code outside the loop ever gets to run - thus this will never work.

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:

// this won't work!
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 by code outside this loop.

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();
    }
}
Windhoek answered 2/3, 2014 at 9:36 Comment(2)
this is misleading that while(flag==false) {} is the answer at first glance...Phrenetic
@Phrenetic - Fair enough. I edited the first couple paragraphs.Windhoek
C
41

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://mcmap.net/q/159874/-wait-until-a-condition-is-true

Continue answered 5/10, 2018 at 3:23 Comment(5)
This is the only solution I've see which easily allows you to "wait" on a signal, yet not "return" from an myFunction until the condition is satisfied.Severen
I've tried the top couple answers and this one has by far worked the best. Not only is it the easiest and cleanest, but it makes the most logical and syntactic sense. Thanks!Sinotibetan
I would prefer the conditional operator: conditionFunction() ? resolve() : setTimeout(() => poll(resolve), 400)Wain
Seems a good solution but could be tidied up slightly - have posted an answer to do the tidying.Tuba
Instead of setTimeout, could you use a Proxy object to listen to changes to the flag variable?Circosta
O
38

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

Okeefe answered 6/11, 2018 at 21:0 Comment(1)
An example of how this code is may be used: (1) At first, lock is false. (2) Some code calls lockable. That code evaluates if (lock) to false, so it continues: it sets lock to true, then goes on to execute some logic. In the meantime: (3) Some other code calls lockable. That code, however, evaluates if (lock) to true, so it awaits on the promise, until an unlocked event will be emitted. (4) Back to the first calling code: It finishes its logic, sets lock to false, and emits an unlocked event. (5) The other code can now continue its execution.Bantling
E
29

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)
Etherize answered 2/10, 2018 at 14:31 Comment(6)
This one really intrigues me - can someone explain how the non-promised await inside the loop effects JS event-loop and prevents the app from hanging?Polemoniaceous
@Polemoniaceous - await null - The function 'returns' at this point, and then continues when the promise wrapper of null resolves.Sole
This doesn't seem that helpful, because the whole rationale of await is to allow you to write code that looks synchronous. Yet here we've got the exact same problem of the "do something..." being embedded in a callback.Severen
instead of await null, a slight sleep could be beneficial depending on your use case. await new Promise(resolve => setTimeout(resolve, 10))Aperient
I honestly don't see how this is easier than just a setTimeout in an if then inside the function. The async/await adds virtually nothing here.Spacial
As "cool" as this may look, how does this solve anything? The code doesn't actually wait for meaningOfLife=true, does it? I mean yes as one point the variable will be set but how does that help with OPs question?Linguini
P
22

I solved this issue by implementing the method below.

const waitUntil = (condition, checkInterval=100) => {
    return new Promise(resolve => {
        let interval = setInterval(() => {
            if (!condition()) return;
            clearInterval(interval);
            resolve();
        }, checkInterval)
    })
}

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

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

const waitUntil = (condition, checkInterval=100) => {
    return new Promise(resolve => {
        let interval = setInterval(() => {
            if (!condition()) return;
            clearInterval(interval);
            resolve();
        }, checkInterval)
    })
}

async function start() {
  let flag = false;
  
  console.log('wait 5 sec');
  
  setTimeout(()=> {flag=true}, 5000); // set flag=true after 5 seconds
  
  await waitUntil(() => flag==true ); // wait
  
  console.log('do something when flag is true...'); 
}

start();
Prestidigitation answered 21/11, 2020 at 20:13 Comment(0)
B
21
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'))
Butyrate answered 9/1, 2018 at 23:16 Comment(0)
S
12

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
};
Seek answered 6/7, 2018 at 14:35 Comment(1)
Does delay need to be async?Edaedacious
T
9

Simplest in terms of readability of calling code and brevity of implementing code:

const until = (predFn) => {
  const poll = (done) => (predFn() ? done() : setTimeout(() => poll(done), 500));
  return new Promise(poll);
};

Example calling code:

await until(() => { myBankBalance > 1000000 });

More detailed example:

https://replit.com/@SteveChambers1/Javascript-until-function?v=1

Tuba answered 23/5, 2022 at 15:19 Comment(0)
A
4

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)
        }
}
Accidie answered 11/2, 2017 at 6:2 Comment(0)
N
4

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.

Newberry answered 6/5, 2020 at 11:3 Comment(0)
S
4

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))
Savitt answered 18/10, 2021 at 10:21 Comment(0)
L
3

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);
Lien answered 16/7, 2019 at 13:55 Comment(0)
W
2

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.

Wimbush answered 19/5, 2020 at 22:21 Comment(0)
S
2

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

}
Slater answered 23/5, 2021 at 19:14 Comment(1)
It seems like your resolveAfter2Seconds function is runs every two seconds until the flag is true. Have you run the code on a local machine? It doesn't seem to do anything asynchronous.Mocambique
A
2

Modern and simple solution

async function waitUntil(condition, time = 100) {
    while (!condition()) {
        await new Promise((resolve) => setTimeout(resolve, time));
    }
}

Usage

async function foo() {
  await waitUntil(() => flag === true);
  console.log('condition is met!');
}
Ancel answered 25/1, 2023 at 13:14 Comment(1)
This worked perfectly for what I was doing, thanks!Shaffert
C
1

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
}
Causalgia answered 5/1, 2019 at 22:18 Comment(0)
Y
1

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);
 }
Yeisk answered 7/2, 2019 at 16:11 Comment(0)
G
1

there is a node package delay very easy to use

const delay = require('delay');

(async () => {
    bar();

    await delay(100);

    // Executed 100 milliseconds later
    baz();
})();
Gladis answered 6/2, 2020 at 12:53 Comment(0)
U
1

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" 
Unnecessarily answered 1/2, 2021 at 6:23 Comment(0)
B
1

By using async/await together with Promise/resolve, you can solve this by wrapping the predicate or flag into this class that allows for waiting it to be true.

This prevents consuming CPU resource because of the polling.

// The wrapper
class WaitFlag {
    private _lock: Promise<void> = new Promise(() => {});
    private _resolve = () => {};

    setFlag = async () => {
        this._lock = new Promise((resolve) => {
            this._resolve = resolve;
        });
    }

    unsetFlag = () => {
        this._resolve();
    }

    waitFlagUnset = async () => {
        await this._lock;
    }
}

// Your code
// Need to change your flag to this data type everywhere
var flag = new WaitFlag();
async function myFunction(number) {

    var x=number;
    ...
    ... more initializations
    //here need to wait until flag==true
    // wait for flag to be unset
    await flag.waitFlagUnset();
    // set the flag to block others from using the resource if you need to
    await flag.setFlag();

    ...
    ... do something

}

// At some other place, unset the flag
flag.unsetFlag();
Backbreaking answered 31/5, 2023 at 5:46 Comment(0)
A
0

//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(); 
  
  
  
  
  
  
Ayres answered 13/9, 2018 at 8:8 Comment(0)
M
0

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");
});
Mcminn answered 15/8, 2019 at 18:56 Comment(0)
T
0

Found my solution above to play multiple audio lists as following;

let flag = false, AudioDuration=3000;
function AudioPlayer(t){setTimeout((t)=> {flag=true}, AudioDuration*t); } 
// set flag=true player ends
const waitUntil = (condition, checkInterval=200) => {
return new Promise(resolve => { let interval = setInterval(() => {if (!condition()) return;clearInterval(interval);resolve();}, checkInterval)  } );
}
/* Asyncronous looping*/
async function start() { 
        for (var i = 1; i < 5; i++) { 
            AudioPlayer(i);console.log(i,'async wait durations');
            await waitUntil( () => flag==true ); // wait audio ends
            console.log('still in loop to play next  when AudioPlayer end is=>>', flag); flag = false;
        }
    }
start();
Tribunal answered 9/4, 2023 at 1:19 Comment(0)
S
-1

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;
}
Sapphirine answered 28/1, 2021 at 21:34 Comment(2)
this will check only one time ?Yautia
The loop runs for 5 seconds and always checks if the flag is still true or falseSapphirine

© 2022 - 2024 — McMap. All rights reserved.