Search code examples
javascripthtmlsettimeout

setTimeout in a for loop with varying time


I have a array of different objects, each object contain a time property of different values.

I would like to loop for this array, inside have a setTimeout function, the time would be the time property of each object.

Therefore, the result I want is

  1. after 10s, print the name of first object
  2. after 20s, print the name of 2nd obj.
  3. ...
  4. ...
  5. after 5s, print the name of last obj.

However, the below code will execute in an accumulation of total 20s, which is print obj 3 & 5 when time = 5s, after 5s, print obj 1, after 10s, print obj 2 & 4.

const data = [
{name: "Warm up", timeFormat: "00:10", time: 10},
{name: "High interval", timeFormat: "00:20", time: 20},
{name: "Low Interval", timeFormat: "00:05", time: 5},
{name: "High interval", timeFormat: "00:20", time: 20},
{name: "Low Interval", timeFormat: "00:05", time: 5},
]

function renderTimer(data) {
  for (let i = 0; i < data.length; i++) {
    const eachName = data[i].name;
    const eachTime = data[i].time;

    setTimeout(() => {
      console.log(eachName);
    }, eachTime * 1000);
  }
}

renderTimer(data);

What is the problem of my code? OR any other ways to achieve the result I want?

Thanks so much!


Solution

  • What happens, is that the program races through the for loop, and sets up the Timeouts almost immediatley relative to t=0s. If you want to use setTimeout(), you have to cumulate the timing yourself:

    const data = [
    {name: "Warm up", timeFormat: "00:10", time: 10},
    {name: "High interval", timeFormat: "00:20", time: 20},
    {name: "Low Interval", timeFormat: "00:05", time: 5},
    {name: "High interval", timeFormat: "00:20", time: 20},
    {name: "Low Interval", timeFormat: "00:05", time: 5},
    ]
    
    function renderTimer(data) {
      var timing = 0;
      for (let i = 0; i < data.length; i++) {
        const eachName = data[i].name;
        timing += data[i].time;
    
        setTimeout(() => {
          console.log(eachName);
        }, timing * 1000);
      }
    }
    
    renderTimer(data);