javascript - 嵌套的 setTimeout() 调用在 JavaScript 中未按正确的顺序运行?

标签 javascript

我试图迭代一个数组,然后在每次迭代中执行 2 个步骤(我们称之为步骤 1 和步骤 2)。每次迭代之间以及步骤 1 和步骤 2 之间应该存在延迟。为了添加延迟,我使用 setTimeout() 方法。

基本上,类似于 -

对于 i 从 0 到 array.length

执行第 1 步

等待2-5秒

执行步骤 2 并增加 i

等待5-9秒并继续循环

下面是我的代码(来自相关问题 - How to run setTimeout() with a random interval in each iteration in javascript? )-

function displayValue(){
   var l = ['a' , 'b', 'c'];
   var delay = 17000;
   var i = 0;
   function timerFunction(i){
      if(i === l.length)
          return;
      setTimeout(()=>{
         console.log("Step 1 - Iteration  - " + i + " - " + l[i] + "  -  " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds());
         setTimeout(() => {
           console.log("Step 2 - Iteration - " + i + " - " + l[i] + "  -  " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds());
           //i++ should probably be here but then i is never incremented
        }, 2000 + Math.floor(Math.random() * 3000));
     i++;
     timerFunction(i);
   }, delay);
   delay = 5000 + Math.floor(Math.random() * 3500);
   } 
   timerFunction(i);
 }

 displayValue();

当我运行上面的代码时,对于第一次之后的所有迭代,步骤 2 在步骤 1 之前打印,并且循环运行超过 array.length。输出类似于 -

第 1 步 - 迭代 - 0 - a - 9:17:14

第 2 步 - 迭代 - 1 - b - 9:17:18

第 1 步 - 迭代 - 1 - b - 9:17:21

第 2 步 - 迭代 - 2 - c - 9:17:24

第 1 步 - 迭代 - 2 - c - 9:17:28

第 2 步 - 迭代 - 3 - 未定义 - 9:17:30

我怀疑这是因为,我需要在内部 setTimeout() 中增加 i ,但是当我将 i++; 移动到那里时,它完全停止增加,可能是因为它成为该方法中的局部变量。有没有办法在内部 setTimeout() 中通过引用传递 i ?或者其他一些解决方案,以防我完全关闭?

最佳答案

您的问题是您正在继续第一个 setTimeout 回调的循环,而此时,第二个回调仍未触发。

因此,您需要的只是从第二级超时内递归调用 timerFunction

function displayValue() {
  var l = ['a', 'b', 'c'];
  var delay = 1000;
  timerFunction(0);

  function timerFunction(i) {
    if (i === l.length)
      return;

    setTimeout(() => { // level 1
      console.log("Step 1 - Iteration  - " + i + " - " + l[i] + "  -  " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds());
      // we start level2 timeout
      setTimeout(() => {
        console.log("Step 2 - Iteration - " + i + " - " + l[i] + "  -  " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds());
        // only when this one is done, we start again
        timerFunction(++i);
      }, 500 + Math.floor(Math.random() * 500));
    }, delay);
    delay = 1000 + Math.floor(Math.random() * 800);
  }
}

displayValue();

但请注意,这与您对应该发生的情况的描述不符。这是:

function displayValue() {
  var l = ['a', 'b', 'c'];
  timerFunction(0);

  function timerFunction(i) {
    if (i === l.length) {
      return;
    }
    // Do Step 1
    level1();

    function level1() {
      console.log("Step 1 - Iteration  - " + i + " - " + l[i] + "  -  " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds());
      // Wait for 2-5seconds (here /10)
      setTimeout(level2, 200 + Math.floor(Math.random() * 300));
    }

    function level2() {
      // Do Step2
      console.log("Step 2 - Iteration - " + i + " - " + l[i] + "  -  " + new Date().getHours() + ":" + new Date().getMinutes() + ":" + new Date().getSeconds());
      // and increment i
      i++;
      // wait for 5-9 seconds and continue the loop
      setTimeout(() => timerFunction(i), 500 + Math.round(Math.random() * 400));
    }

  }
}
displayValue();

如果您可以使用async/await语法,那么您可以将其重写得更简洁:

displayValue();

function displayValue() {
  const l = ['a', 'b', 'c'];
  return iterate(0);

  async function iterate(i) {
    if(i >= l.length) return;
    step(1, i);
    await wait(200, 500);
    step(2, i);
    await wait(500, 900);
    return iterate(++i);
  }
  function step(type, index) {
    var d = new Date();
    console.log("Step " + type +
      " - Iteration  - " + index +
      " - " + l[index] +
      " -  " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()
    );  
  }
}
function wait(min, max=min) {
  const delay = min + Math.floor(Math.random() * (max - min));
  return new Promise(res =>
    setTimeout(res, delay)
  );
}

关于javascript - 嵌套的 setTimeout() 调用在 JavaScript 中未按正确的顺序运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55253527/

相关文章:

javascript - 选项值数据绑定(bind)不起作用

javascript - 是否可以将 iframe 值放在 textarea 中?

php - 从jquery中的复选框列表中获取数据数组

javascript - 适用于所有页面的用户脚本会导致 StackExchange 出现问题

javascript - 如何使用 jquery 从 Sharepoint 用户配置文件数据库获取用户

javascript - React Native - 违反不变性 : Objects are not valid as a React Child (Using Node JS for backend)

javascript - ReactJS - this.state 中的数组在删除时正确更新,但结果直到后来的状态更改才呈现?

javascript - Webrtc 远程视频流不工作

javascript - 数组连续元素之和

javascript - 使用 .prototype 的简单场景