Max
Max

Reputation: 2783

Call async function while pushing the same function on array

I have this code:

var queue = [];
var allParserd = [];

_.each(webs, function (web) {
    queue.push(function () {
        WebsitesUtils.parseWebsite(web, function (err, parsed) {
            allParserd.push(parsed);
        });
    });
});

Promise.all(queue).then(function (data) {
    console.log(allParserd);
});

Basically I need to fetch all my webs and be sure to give the result after that every parsing is done. the function parseWebsite return the correct data, but in this way is not called and allParsed return just as an empty array. I'm sure that I miss some things, I've started to use the promises just from some days.

If you need some more information just tell me.

P.s. I want that all the functions to start at the same time; I don't want to wait for each one response for going forward.

Upvotes: 1

Views: 207

Answers (3)

Bergi
Bergi

Reputation: 664970

Promise.all doesn't take a queue of functions to execute. It expects an array of promises which represent the results of the many concurrently running (still pending) requests.

The first step is to have a function that actually returns a promise, instead of only executing a callback. We can use

function parseWebsite(web) {
    return new Promise(function(fulfill, reject) {
        WebsitesUtils.parseWebsite(web, function (err, parsed) {
            if (err)
                reject(err);
            else
                fulfill(parsed);
        });
    });
}

or simply use promisification that does this generically:

var parseWebsite = Promise.promisify(WebsitesUtils.parseWebsite, WebsitesUtils);

Now we can go to construct our array of promises by calling that function for each site:

var promises = [];
_.each(webs, function (web) {
    promises.push(parseWebsite(web));
});

or just

var promises = _.map(webs, parseWebsite);

so that in the end we can use Promise.all, and get back our allParsed array (which even is in the same order as webs was!):

Promise.all(promises).then(function(allParsed) {
    console.log(allParsed);
});

Bluebird even provides a shortcut function so you don't need promises:

Promise.map(webs, parseWebsite).then(function(allParsed) {
    console.log(allParsed);
});

Upvotes: 1

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276406

Tagged with Bluebird so let's use it:

First, let's convert your callback API to promises:

  Promise.promisifyAll(WebsitesUtils);

Now, let's use .map to map every item in webs to it being parsed parseWebsite:

Promise.map(webs, function(item){
    return WebsitesUtils.parseWebsiteAsync(item); // note the suffix
}).then(function(results){
    // all the results are here.
}).catch(function(err){
    // handle any errors
});

As you can see - this is trivial to do with Bluebird.

Upvotes: 2

mscdex
mscdex

Reputation: 106726

Here's how might do it with async:

var async = require('async');

var webs = ...

async.map(webs, function(web, callback) {
  WebsitesUtils.parseWebsite(web, callback);
}, function(err, results) {
  if (err) throw err; // TODO: handle errors better

  // `results` contains all parsed results
});

and if parseWebsite() isn't a prototype method dependent on WebsitesUtils then you could simplify it further:

async.map(webs, WebsitesUtils.parseWebsite, function(err, results) {
  if (err) throw err; // TODO: handle errors better

  // `results` contains all parsed results
});

Upvotes: 0

Related Questions