在迭代到循环的下一次迭代之前完成 FOR 循环内的所有函数

Complete all functions inside a FOR LOOP before iterating to next iteration of the loop

假设我有这样的函数:

var bigArray = [1,2,3,4,5.........n];
for(var i=0; i<bigArray.length; i++){
  if(someCondition){
     setTimeout(function(){
       ..do_stuff..
       callSomeFunction();
     }, someDelayTime);
  }

  if(someCondition){
     setTimeout(function(){
       ..do_stuff..
       callSomeFunction();
     }, someDelayTime);
  }

  if(someCondition){
     setTimeout(function(){
       ..do_stuff..
       callSomeFunction();
     }, someDelayTime);
  }
  .
  .
  .
  .
  .
  .
  .
  .
  if(someCondition){
     setTimeout(function(){
       ..do_stuff..
       callSomeFunction();
     }, someDelayTime);
  }
}


现在我想从这个函数中得到的是,当所有条件都执行了它们的预期任务时,只有到那时它才应该移动到 FOR 循环的下一次迭代。换句话说,FOR 循环中的 i=0 应该更改为 i=1 等等,前提是 FOR 循环内的所有条件都已在当前迭代中完成它们的工作。

目前此代码的行为非常随机(我相信是因为 setTimeout)。我怎样才能按照我的期望完成这项工作?

我最近阅读了有关承诺的内容(对它们了解不多),但我不确定如何在此代码中实现它们,或者它们是否适用于这种情况...

请试试这个:

bigArray = [1, 2, 3, 4, 5.........n];
neededStuff = 10; // Number of finished works you need below
stuffOK = neededStuff;
function mainFunction(i) {

    function loopFunction(i) {
        if (someCondition) {
            setTimeout(function () {
                // .. do_stuff..
                stuffOK++;
                callSomeFunction();
            }, someDelayTime);
        }

        if (someCondition) {
            setTimeout(function () {
                // .. do_stuff..
                stuffOK++;
                callSomeFunction();
            }, someDelayTime);
        }

        if (someCondition) {
            setTimeout(function () {
                // .. do_stuff..
                stuffOK++;
                callSomeFunction();
            }, someDelayTime);
        }
        /*

         ...

         */

        if(someCondition) {
            setTimeout(function () {
                // .. do_stuff..
                stuffOK++;
                callSomeFunction();
            }, someDelayTime);
        }
    }

    if (stuffOK == neededStuff) {
        i++;
        stuffOK = 0; // reinit counter
        loopFunction(i);
    }

    setTimeout('mainFunction(' + i + ');', 100);

}
mainFunction(-1);

希望这能在 promise 链中发挥作用

callSomeFunction1().then(function() {
   callSomeFunction2();
}).then(function() {
   callSomeFunction3();
})

最初的想法来自 of Nina Scholz 一些类似的问题。 如果您不喜欢承诺和延迟对象,这个答案很好。否则 Kris KowalQ library 会是更好的选择。

function Iterator() {
  var iterator = this;
  this.queue = [];

  this.add = function(callback, wait) {
    iterator.queue.push(iterator.wait(wait));

    iterator.queue.push(function() {
      callback();
      iterator.next();
    });
  };

  this.wait = function(wait) {
    return function() {
      setTimeout(iterator.next, wait);
    };
  };

  this.next = function() {
    iterator.queue.length && iterator.queue.shift()();
  };
}

var arr = [1, 2, 3, 4, 5],
  counter = -1;

var iterator = new Iterator();

(function fillNextIteration() {
  if (counter >= arr.length)
    return;
  counter++;
  iterator.add(function() {
    console.log('1 - counter value is ' + counter);
  }, 100);
  iterator.add(function() {
    console.log('2 - counter value is ' + counter);
  }, 100);
  iterator.add(function() {
    console.log('3 - counter value is ' + counter);
  }, 100);
  iterator.add(function() {
    console.log('4 - counter value is ' + counter);
  }, 100);

  iterator.add(fillNextIteration, 100);
  iterator.next();

})();

代码说明

迭代器class有一个队列,它是数组和一些方法:

下一个

当您调用 next() 时,如果队列中有任何回调,它将首先获取并执行。当您调用 Array#shift 时,它会删除 returns 数组中的第一项。当此项是一个函数时,您可以通过在它前面添加括号来调用它。这是扩展版本:

if (iterator.queue.length > 0) {
    var callback = iterator.queue.shift();
    callback();
}

等等

此方法将向队列添加一个额外的回调,在超时后调用下一个方法。这个是为了创造预期的延迟。

添加 此方法以所需的延迟调用等待,然后将另一个函数附加到队列,该队列将调用回调,然后调用 next 以创建回调链 运行.


fillNextIteration 在解释了迭代器之后,函数 fillNextIteration 上还有另一个循环,它从第一次迭代的条件开始,例如:

if (someConditionIsTrue) {
    iterator.add(function() {
        doWhatShallBeDone;
    }, delay);
}

您可以检查所有条件,然后在需要时添加回调,如图所示。 在所有条件完成后添加 fillNextIteration 作为继续循环的最后一个操作。

自调用函数 如您所见,fillNextIteration 是自调用的。 这有助于减少一次调用并像这样工作:

function f(){};
f();

最后一件事 您可以通过调用自身内部的函数来创建循环。如果没有延迟或停止撤销那么这将是一个僵局。所以这也是另一个循环:

(function loop() { setTimeout(loop, delay); })();