here's the code I currently using,
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);
}
}
}
}
then, I will use the function in this way:
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);
});
with this implementation, I can loop through an array with async function and execute the callback function when all elements in the array have been processed.
but now I want to add a delay/interval feature to loopArrayWithAsync()
something like loopArrayWithAsync(array, {interval : 1000}, function (element, finish) {...
, after it processed the first element, it should wait for 1000ms, then starts to process the second element, and vice versa...
I've found another question talking about adding delay to for loop
but it seems to be more complicated while dealing with async functions.
Any answers will be appreciated
============================== update ==============================
this is the function after refactoring,
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);
}
}
}
}());
};
so that I can use the function in this way now:
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);
});
or
loopArrayWithAsync(array, {oneByOne : true}, function (element, finish) {...
loop through the elements one by one
loopArrayWithAsync(array, {interval : 5000, oneByOne : true}, function (element, finish) {...
loop through the elements one by one and with 5 seconds delay
available options :
interval
is the amount of milliseconds between each iteration, default : 0
If oneByOne
is true, the method would only proceed to the next element until finish
has been invoked for the current element, default : false
The code suits my case now, but I will still try the suggested libraries to make life easier, thank you
Please leave a comment if you found that the code can be further improved, looking forward to any suggestions!