4

I am trying to iterate thru array of objects and add some stuff inside these objects using async function in Node.js.

So far my code looks like:

var channel = channels.related('channels');
channel.forEach(function (entry) {

    knex('albums')
        .select(knex.raw('count(id) as album_count'))
        .where('channel_id', entry.id)
        .then(function (terms) {
            var count = terms[0].album_count;
            entry.attributes["totalAlbums"] = count;
        });

});
//console.log("I want this to be printed once the foreach is finished");
//res.json({error: false, status: 200, data: channel});

How can I achieve such a thing in JavaScript?

Lulzim
  • 547
  • 4
  • 9
  • 22

2 Answers2

7

Since you are already using promises, better not to mix that metaphor with async. Instead, just wait for all the promises to finish:

Promise.all(channel.map(getData))
    .then(function() { console.log("Done"); });

where getData is:

function getData(entry) {
    return knex('albums')
        .select(knex.raw('count(id) as album_count'))
        .where('channel_id', entry.id)
        .then(function (terms) {
            var count = terms[0].album_count;
            entry.attributes["totalAlbums"] = count;
        })
    ;
}
  • This should've been the accepted answer. It makes more sense to deal with asynchronism with the same constructs. Since the poster is already using promises, using the 'async' package for this use case alone doesn't make much sense to me. – Ruben Cordeiro Mar 09 '16 at 10:07
1

Use async.each

async.each(channel, function(entry, next) {
    knex('albums')
         .select(knex.raw('count(id) as album_count'))
         .where('channel_id', entry.id)
         .then(function (terms) {
            var count = terms[0].album_count;
            entry.attributes["totalAlbums"] = count;
            next();
         });
}, function(err) {
    console.log("I want this to be printed once the foreach is finished");
    res.json({error: false, status: 200, data: channel});
});

The final callback will be called when all entries are processed.

Barış Uşaklı
  • 13,440
  • 7
  • 40
  • 66
  • Personally I think that you should choose a framework for asynchronicity and stick with it, and not mix metaphors, such as the old callback strategy with promises. Here, since the underlying asynchronous call is promise-based, it makes more sense IMHO to use promise mechanisms to aggregate the results. That will also work better if you want to handle errors, as you probably should. The `async` strategy will require you to add a `.catch(next)` to handle the error situation, whereas using promises throughout, the error simply propagates automatically to the failure branch of a `Promise.all`. –  Mar 21 '15 at 14:08