簡體   English   中英

用異步功能實現for循環延遲的最佳實踐是什么

[英]What is the best practice to implement a delay to for loop with async function

這是我當前使用的代碼,

function loopArrayWithAsync(array, doSthWithElement, finalCallback) {
    var count = 0;
    var _data = [];
    var _errs = [];
    for (var i = 0; i < array.length; i++) {
        doSthWithElement(array[i], function (err, data) {
            count++;
            if (err) {
                _errs.push(err);
            }
            if (data) {
                _data.push(data);
            }
            if (count === data.length) {
                finalCallback(_errs, _data);
            }
        }
    }
}

然后,我將以這種方式使用該函數:

loopArrayWithAsync(array, function (element, finish) {
    // element - element in the array
    asyncFunc(element, function (err, result) {
        if (err) {
            finish(err);
        } else {
            finish(null, result);
        }
    });
}, function (errs, finalData) {
    // when the for loop is finished,
    // i.e. (count === data.length)
    // this callback will be executed
    // errs - array of err from the above callback function
    // finalData - array of result from the above callback function
    outerCallback(errs, finalData);
});

通過此實現,我可以遍歷帶有異步功能的數組,並在處理完數組中的所有元素后執行回調函數。

但現在我想向loopArrayWithAsync()添加延遲/間隔功能

類似於loopArrayWithAsync(array, {interval : 1000}, function (element, finish) {... ,在處理完第一個元素后,應等待1000ms,然后開始處理第二個元素,反之亦然...

我發現了另一個問題,關於在for循環中添加延遲

但是在處理異步函數時,它似乎更加復雜。

任何答案將不勝感激

=============================更新=================== ===========

這是重構后的功能

function loopArrayWithAsync(array, options, doSthWithElement, finalCallback) {
    if (isFunction(options)) {
        finalCallback = doSthWithElement;
        doSthWithElement = options;
        options = {};
    }
    options.interval = options.interval || 0;
    options.oneByOne = options.oneByOne || false;
    var _data = [];
    var _errs = [];
    var count = 0;
    var length = array.length;
    var i = 0;
    (function handleIteration() {
        if (i < length) {
            var element = array[i];
            doSthWithElement(element, function (err, data) {
                if (err) {
                    _errs.push(err);
                }
                if (data) {
                    _data.push(data);
                }
                count++;
                if (count === length) {
                    finalCallback(_errs, _data);
                } else if (options.oneByOne) {
                    if (options.interval) {
                        setTimeout(handleIteration, options.interval);
                    } else {
                        process.nextTick(handleIteration);
                    }
                }
            });
            i++;
            if (!options.oneByOne) {
                if (options.interval) {
                    setTimeout(handleIteration, options.interval);
                } else {
                    process.nextTick(handleIteration);
                }
            }
        }
    }());
};

這樣我就可以以這種方式使用該函數:

loopArrayWithAsync(array, {interval : 1000}, function (element, finish) {
    asyncFunc(element, function (err, result) {
        if (err) {
            finish(err);
        } else {
            anotherAsyncFunc(result, function (err, doc) {
                if (err) {
                    finish(err);
                } else {
                    finish(null, doc);
                }
            });
        }
    });
}, function (errs, finalData) {
    outerCallback(errs, finalData);
});

要么

loopArrayWithAsync(array, {oneByOne : true}, function (element, finish) {...逐一循環遍歷元素

loopArrayWithAsync(array, {interval : 5000, oneByOne : true}, function (element, finish) {...逐一循環並延遲5秒來遍歷元素

可用選項 :

interval是每次迭代之間的毫秒數,默認值: 0

如果oneByOne為true,則該方法將僅繼續到下一個元素,直到已為當前元素調用finish為止,默認為: false

該代碼現在適合我的情況,但是我仍將嘗試使用建議的庫使生活更輕松,謝謝

如果您發現該代碼可以進一步改進,請發表評論,期待任何建議!

您可以使用局部函數進行異步循環。 對於下一次迭代,該函數將延遲調用自身:

function loopArrayWithAsync(array, doSthWithElement, finalCallback, delay) {
  var _data = [], _errs = [], i = 0;
  loop();

  function loop() {
    doSthWithElement(array[i], function (err, data) {
      if (err) {
        _errs.push(err);
      }
      if (data) {
        _data.push(data);
      }
      i++;
      if (i === array.length) {
        finalCallback(_errs, _data);
      } else {
        window.setTimeout(loop, delay);
      }
    }
  }

}

要以一定間隔啟動呼叫,而不必在兩次呼叫之間有延遲,只需在不同時間使用setInterval

function loopArrayWithAsync(array, doSthWithElement, finalCallback, delay) {
  var _data = [], _errs = [], count = 0;
  for (var i = 0; i < array.length; i++) {
    window.setTimeout(function() {
      doSthWithElement(array[i], function (err, data) {
        if (err) {
          _errs.push(err);
        }
        if (data) {
          _data.push(data);
        }
        count++;
        if (count === array.length) {
          finalCallback(_errs, _data);
        }
      });
    }, i * delay);
  }
}

如@thefourtheye所建議,您可以使用Promises的概念,而Bluebird是一個快速而完善的庫。 Promise.settle可讓您解決和拒絕諾言,然后檢查結果。

function loopArray(array) {
    var arrayOfPromises = [];
    for (var i = 0; i < array.length; i++) {
        arrayOfPromises.push(doSomethingAsync(array[i]));
    }

    Promise.settle(arrayOfPromises).then(function (results) {
        console.log("All async calls done! You can inspect the result!");
        console.log(results);
    });
}


function doSomethingAsync(item) {
    return new Promise(function(resolve, reject){
        //Do you async work here!
        console.log("Entering async function call " + item);
        if(item === "three"){
            reject("bad value!");
        }
        resolve(item + " promise done!");
    });
}


loopArray(["one","two","three"]);

我對以下示例做了一個JSFiddle 使用異步函數,promise可以為您提供很多幫助,所以我真的建議您研究一下。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM