Ted Logan
Ted Logan

Reputation: 414

setTimeout in a loop. How to get the correct order

Im trying to call a function in a loop for different timeouts or delays.

for (var i = 0; i < 10; i++) {        
  callDelayedFunction(i);
}

function callDelayedFunction(i) {
  setTimeout(function () {
    console.log(i);        
  }, getRandomInt(1500, 4500) * i);
}

I expect

1,2,3,4,5,6,7,8,9

But I get

1,2,3,4,7,8,5,6,9

How can I solve this problems?

Upvotes: 3

Views: 104

Answers (3)

Rahul Bhobe
Rahul Bhobe

Reputation: 4451

You could try this. The code choses a random time within a 3 second window. This sets up the window based on the index value.

for (var i = 0; i < 10; i++) {        
    callDelayedFunction(i);
}

function callDelayedFunction(i) {
    let windowLength = 3000;
    let startTime = 1500;
    setTimeout(function () {
        console.log(i);        
    }, startTime + getRandomInt(windowLength*i, windowLength*(i+1)));
}


function getRandomInt(a, b) {
  return Math.floor((Math.random()*(b-a)) + a);
}

Upvotes: 0

mbojko
mbojko

Reputation: 14679

You shouldn't expect the numbers to be printed out in order, if you set random timeouts and not take any steps to guarantee that n+1-th iteration is fired after n-th iteration.

Without changing the paradigm, you could solve the task by introducing an auxiliary variable like this - every next setTimeout is called with delay parameter bigger than the previous one:

var timeoutLimit = 0;

function getRandomInt(low, high) {
  return Math.floor(Math.random() * (high - low) + low);
}

for (var i = 0; i < 10; i++) {
  callDelayedFunction(i);
}

function callDelayedFunction(i) {
  var delay = getRandomInt(150, 450) + 1;
  timeoutLimit += delay;
  setTimeout(function() {
    console.log(i);
  }, timeoutLimit);
}

Upvotes: 1

TKoL
TKoL

Reputation: 13902

Here's one way, using async/await:

function callDelayedFunction(i) {
  return new Promise(resolve => {
    setTimeout(function() {
      console.log(i);
      resolve();
    }, getRandomInt(1500, 4500) * i);
  })

}

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

async function run() {
  for (var i = 0; i < 10; i++) {
    await callDelayedFunction(i);
  }
}

run();

Upvotes: 4

Related Questions