嵌套setTimeout()调用在javascript中的执行顺序不正确?

时间:2019-03-20 04:18:11

标签: javascript

我正在尝试遍历数组,然后在每次迭代中执行2个步骤(我们将其称为步骤1和步骤2)。在每次迭代之间以及在步骤1和步骤2之间应该有一个延迟。为增加延迟,我使用了setTimeout()方法。

基本上,类似-

对于我,从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?还是其他解决方案,以防万一我完全离开?

1 个答案:

答案 0 :(得分:1)

您的问题是您正在从第一个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)
  );
}