Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling then before or after Promise.all

Currently I have following code:

var detailPromises = links.map(function (link) { return requestP(link) });

var oldPollNames = [];
// add a database call to the promises as it also can resolved during detail fetching
detailPromises.push(db.polls.findAsync({}, {title: 1}));
return Promise.all(detailPromises)
    .then(function (data) {
        oldPollNames = data.pop().map(function (item) { return item.title; });
        return data;
    })
    .then(function (htmls) {
        var newPolls = [];
        htmls.forEach(function (i, html) {
            // some processing of html using oldPollNames (newPools.push...)
        });
        return newPolls;
    })
    .then(/* insert into db */);

What I'm doing is: waiting for db + waiting for html requests and then process booth.

I'm wondering if it would make more sense / be more performant to do following:

var detailPromises = links.map(function (link) { return requestP(link) });

return db.polls.findAsync({}, {title: 1}).then(function(polls) {
    var oldPollNames = polls.map(function (item) { return item.title; });
    var newPolls = [];

    detailPromises = detailPromises.map(function (p) {
        return p.then(function (html) {
            // some processing of html using oldPollNames (newPools.push...)
        })
    });

    return Promise.all(detailPromises)
        .done(function () {
            // insert newPolls into db
        });
});

The advantage of the second approach imo is that each request gets (already) handled when it is done and can do it's procesing before all / other promises are fulfilled.

like image 515
velop Avatar asked Dec 12 '25 09:12

velop


1 Answers

I'm wondering if it would make more sense / be more performant

Yes, it would be more performant to process each html request separately and as fast as possible, instead of waiting for all of them and then processing them together in a huge loop. Not only will they processed earlier, you also avoid a possibly long-running loop of heavy processing.

However, the approach also has its drawbacks: it's more complicated to implement. The code you've given is prone to reporting Unhandled Rejections if any of the detailPromises rejects before the database query fulfills, or if any of them rejects and the database query is rejected as well. To prevent that, you'll need to use Promise.all on all the promises anyway:

var detailPromises = links.map(requestP);

var resultPromise = db.polls.findAsync({}, {title: 1}).then(function(polls) {
    var oldPollNames = polls.map(function(item) { return item.title; });
    var newPollPromises = detailPromises.map(function(p, i) {
        return p.then(function(html) {
            // some processing of html
        });
    });

    return Promise.all(newPollPromies) // not the detailPromises!
    .then(function(newPolls) {
        // insert newPolls into db
    });
});
return Promise.all([resultPromise].concat(detailPromises)).then(function(r) {
    return r[0];
});
like image 199
Bergi Avatar answered Dec 14 '25 22:12

Bergi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!