Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function with callback in foreach loop

I'm trying to use a function with callback in forEach loop.

I need to wait for execution to complete before moving on to next step.

Here's my code:

const arr = '6,7,7,8,8,5,3,5,1'

const id = arr.split(',');

const length = id.length;


id.forEach( (x, index) => {
  (function FnWithCallback () {
    setTimeout(() => { console.log(x) }, 5000);
  })();
});

console.log('done');

I came up with a hack:

const arr = '6,7,7,8,8,5,3,5,1'

const id = arr.split(',');

const length = id.length;

const fn = () => {
  return new Promise (resolve => {
    id.forEach( (id, index) => {
      setTimeout(() => {console.log(id)}, 3000);

      if(index === (length - 1))
         resolve();
    })
  })
}

fn().then(()=> {
  console.log('done');
})

But the hack seems to be broken.

Can I have a real solution to this? A NPM package would be really helpful.

Note: I had a look at async.js. I'm not sure if that is something I want since I'm trying to avoid callback hell.

like image 982
Dev Aggarwal Avatar asked Aug 12 '26 17:08

Dev Aggarwal


1 Answers

The solution is to promisify the callback function and then use Array.prototype.map() coupled with Promise.all():

const arr = '6,7,7,8,8,5,3,5,1'

function FnWithCallback (id, cb) {
  setTimeout(cb, 1000, id)
}

const promisified = id => new Promise(resolve => {
  FnWithCallback(id, resolve)
})

const promises = arr.split(',').map(promisified)

Promise.all(promises).then(id => {
  console.log(id)
  console.log('Done')
})

If your callback API follows the Node.js convention of (error, result) => ..., then you should use util.promisify() to promisify the function, or check the documentation to see if omitting the callback argument will cause the call to return a promise, since a lot of packages provide promise-based APIs out-of-the-box now.

like image 178
Patrick Roberts Avatar answered Aug 14 '26 07:08

Patrick Roberts