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

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-10 15:27:49

问题


Say i have a function like :

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


Now what i want from this function is that when all of the conditions have performed their intended task, only then it should move to the next iteration of FOR loop. In other words, i=0 in FOR LOOP should change to i=1 and so-on iff all of the conditions inside the FOR loop have completed their job in current iteration.

Currently behaviour of this code is very random (because of setTimeout i believe). How can i make this work as per my expectations?

I recently read about promises (don't know much about them) but i'm not sure how to implement them in this code or if they will work in this case...


回答1:


The original idea came from the answer of Nina Scholz on some similar question. this answer is good if you don't like promises and deferred object. Othewise Kris Kowal's Q library would be a better choice.

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

})();

Code Explanation

Iterator class has one queue which is and array and some methods:

next

when you call next() if there is any callback in queue it will fetch first and execute that. when you call Array#shift it removes and returns first item from array. When this item is a function then you can invoke it by adding parentheses in front of it. here is the expanded version:

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

wait

This method will add an extra callback to queue which after a timeout calls the next method. this one is for creating the expected delay.

add This method calls the wait with desired delay then attaches another function to queue which will call the callback and then calls next to make callback chain running.


fillNextIteration after explaining the iterator there is another loop here on function fillNextIteration this starts with the conditions for the first iteration for example:

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

you can check all conditions and then if required add the callback as shown. after all condition finished add fillNextIteration as last action to continue the loop.

self invoking function As you can see fillNextIteration is self invoked. This helps to reduce one invoke and works like this:

function f(){};
f();

Last thing to mention you can create a loop by calling a function inside itself. if there is no delay or stop for revoke then it would be a deadlock. So this is another loop as well:

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



回答2:


Try this please :

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



回答3:


Hope this will work from promise chaning

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


来源:https://stackoverflow.com/questions/38159088/complete-all-functions-inside-a-for-loop-before-iterating-to-next-iteration-of-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!