1

I want to get data from db for several times. How to set a loop to execute getData() function in interval like 200ms. And if one of them success, rest of them won't be triggered. It's asynchronous method, and different from question here: Asynchronous Process inside a javascript for loop

for(var i = 0; i < 3; i++){
setTimeout(getData,200);}

This will end up with the output time interval is very close instead of 200ms, since they are asynchronous. Three "setTimeout" are triggered in a short time. like 0.001s 0.002s 0.003s, the output time is 0.201, 0.202, 2.203.

getData() returns a promise. But it can be normal function as long as it works.

DD Jin
  • 355
  • 1
  • 3
  • 15
  • I would suggest moving away from callbacks and towards the new promise paradigm – EDToaster Jul 10 '19 at 21:10
  • It would be helpful to know what flavor of async `getDB` is. Does it return a promise? Take a callback? – Mark Jul 10 '19 at 21:15
  • @MarkMeyer It can be a normal function. I pack it here to return promise, since I need some method after this. – DD Jin Jul 10 '19 at 21:43
  • Lots of options covered here: [How to sequence asynchronous operations](https://stackoverflow.com/questions/29880715/how-to-synchronize-a-sequence-of-promises/29906506#29906506). – jfriend00 Jul 10 '19 at 23:35

3 Answers3

1

You can do this by waiting for the setTimeout to finish before executing the next setTimeout

I don't believe this is possible with callbacks, as is the case with setTimeout, so you should transform it into a promise-based call

const promiseSetTimeout = timeout => new Promise(r => setTimeout(r, timeout));

const waitManyTimes = async () => {
    for(let i = 0; i < 3; i++) {
        await promiseSetTimeout(200);
        // do something here, like getDB 
        console.log(i);
    }
}

waitManyTimes();
EDToaster
  • 3,160
  • 3
  • 16
  • 25
0

Don't use a loop. Have the function call setTimeout() to run itself again if it fails.

var i = 0;

function callGetDB() {
  getDB().then(db => {
    // use DB
  }).catch(() => {
    if (i++ < 3) {
      setTimeout(callGetDB, 200);
    }
  });
}

I'm assuming the asynchronous function getDB() returns a promise.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • What if they can all get the data successfully. Can I get the thing like "as soon as one of them receive the data, rest of them stop". Your code will execute for three times if first one already got the answer, right? – DD Jin Jul 10 '19 at 21:53
  • The `.catch()` is only executed when the promise fails. So it stops when one of them succeeds. – Barmar Jul 10 '19 at 21:55
  • I am using your solution. But I just find that if I successfully get the data in second try and resolve() it, it can't be passed to the next funciton in code like . callGetDb().then(data)=>{}. 'data' will be null – DD Jin Jul 16 '19 at 22:50
  • I post specific code here https://stackoverflow.com/questions/57066813/how-can-asynchronous-method-in-recursion-return-result-correctly . Could you please take a look? – DD Jin Jul 16 '19 at 23:55
0

Using async/await:

let sleep = ms => new Promise(r => setTimeout(r, ms));

let main = async() => {
  for(var i = 0; i < 3; i++) {
    let db = getDB();
    if (db)
      return db;
    await sleep(200);
  }
};
junvar
  • 11,151
  • 2
  • 30
  • 46
  • `getDB` is async right? What are you testing with `if (db)`? If `getDB()` returns a promise, which isn't clear in the question, you'll need to `await` it. If it takes a callback... – Mark Jul 10 '19 at 21:13