最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Executing a callback function after .forEach finishes - Stack Overflow

programmeradmin1浏览0评论

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
Add a ment  | 

3 Answers 3

Reset to default 5

This 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.

发布评论

评论列表(0)

  1. 暂无评论