I'm trying to execute a function after a forEach loop has pleted all iterations.
This answer provides an interesting solution, but I can't get it to work.
Here's the code I adapted, creating a simple asyncFunction().
function callback () { console.log('all done'); }
function asyncFunction(item) {
console.log("in async function, item is " + item)
}
var itemsProcessed = 0;
[1, 2, 3].forEach((item, index, array) => {
asyncFunction(item, () => {
itemsProcessed++;
console.log("in callback area, itemsProcessed is " + itemsProcessed )
if(itemsProcessed === array.length) {
callback();
}
});
});
As visible in this JSfiddle, the script correctly executes the async function, but fails to enter the part which increments itemsProcessed
and should trigger the callback()
function.
I'm not too familiar with the fat arrow functions, so maybe the error es from their usage.
Can anyone explain why the script isn't behaving as expected?
I'm trying to execute a function after a forEach loop has pleted all iterations.
This answer provides an interesting solution, but I can't get it to work.
Here's the code I adapted, creating a simple asyncFunction().
function callback () { console.log('all done'); }
function asyncFunction(item) {
console.log("in async function, item is " + item)
}
var itemsProcessed = 0;
[1, 2, 3].forEach((item, index, array) => {
asyncFunction(item, () => {
itemsProcessed++;
console.log("in callback area, itemsProcessed is " + itemsProcessed )
if(itemsProcessed === array.length) {
callback();
}
});
});
As visible in this JSfiddle, the script correctly executes the async function, but fails to enter the part which increments itemsProcessed
and should trigger the callback()
function.
I'm not too familiar with the fat arrow functions, so maybe the error es from their usage.
Can anyone explain why the script isn't behaving as expected?
Share Improve this question asked May 20, 2018 at 0:19 sc28sc28 1,2136 gold badges28 silver badges52 bronze badges 2-
You are passing a function as second argument to
asyncFunction()
when you call it but function declaration doesn't expect second argument and never calls the callback passed to it – charlietfl Commented May 20, 2018 at 0:24 -
That makes sense, thanks. However I'm not sure which argument to declare second. Obviously
asyncFunction(item, ())
doesn't work. Could you please explain more explicitly how to tackle this second argument? – sc28 Commented May 20, 2018 at 0:28
3 Answers
Reset to default 5This is a case where the more modern approach is to use promises
function asyncFunction(item) {
// return a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("in async function, item is " + item)
// resolve promise when data is ready
resolve(item)
}, Math.random()*2000)// random delay to stagger order of returns
})
}
// create array of promises
let promiseArray = [1, 2, 3].map(asyncFunction);
// runs when all promises are resolved
Promise.all(promiseArray).then(results => {
console.log('all done')
// results array will be in same order as original array
console.log('results are: ', results)
})
.as-console-wrapper {max-height: 100%!important;top:0}
Because you want to pass a callback function as 2nd argument to asyncFunction
, you need to specify that there'll be a callback function as 2nd argument, and you need to call that like this:
function asyncFunction(item, cb) {
console.log("in async function, item is " + item)
cb()
}
Also, your code can be rewrite to make it easier to understand the use of callback function. Your code:
[1, 2, 3].forEach((item, index, array) => {
asyncFunction(item, () => {
itemsProcessed++;
console.log("in callback area, itemsProcessed is " + itemsProcessed )
if(itemsProcessed === array.length) {
callback();
}
});
});
is the same as:
[1, 2, 3].forEach((item, index, array) => {
function cbFunc() {
itemsProcessed++;
console.log("in callback area, itemsProcessed is " + itemsProcessed )
if(itemsProcessed === array.length) {
callback();
}
}
asyncFunction(item, cbFunc);
});
Map each of the elements to a Promise, then use Promise.all()
.
Promise.all([1, 2, 3].map(async num => num));
Of course, you can do something more sophisticated inside of the async function if you want.
Promise.all([1, 2, 3].map(num =>
{
return new Promise((reject, resolve) =>
{
setTimeout(() => resolve(num), 5000);
})
}));
And if the code you're executing is synchronous or involves a timeout, then use the Promise
constructor instead of an async function.