具有不同时间的for循环中的setTimeout

setTimeout in a for loop with varying time

我有一个不同对象的数组,每个对象包含不同值的时间属性。

我想循环这个数组,里面有一个setTimeout函数,时间就是每个对象的时间属性。

所以我想要的结果是

  1. 10秒后,打印第一个对象的名称
  2. 20s后,打印第二个对象的名字。
  3. ...
  4. ...
  5. 5 秒后,打印最后一个对象的名称。

但是下面的代码会累计执行20s,即time = 5s时打印obj 3 & 5,5s后打印obj 1,10s后打印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);

我的代码有什么问题?或任何其他方式来实现我想要的结果?

非常感谢!

发生的事情是,程序在 for 循环中竞速,并几乎立即设置了相对于 t=0s 的超时。如果要使用setTimeout(),就得自己累计时间:

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);

您也可以像这样在递归函数中执行此操作:

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},
]

const renderTimer = (data, i = 0) => {
  setTimeout(() => {
    console.log(data[i].name);
    
    // Call for next data
    if(i < data.length - 1)
      renderTimer(data, i + 1);
  }, data[i].time * 1000);
}

renderTimer(data);

你可以使用 async/await and Promises

它的工作原理是 await new Promise(...) 停止当前函数直到 Promise 完成

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},
]

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

    await new Promise(res => {
      setTimeout(() => {
        console.log(eachName);
        // resolve the promise once the log is done
        res()
      }, eachTime * 100)}
    )
    // can't arrive here until the setTimeout is finalized
  }
}

renderTimer(data);

你可以这样做:

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},
]

var time = 0;

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

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

renderTimer(data);