greengold
greengold

Reputation: 1333

Promise returned from method gets undefined

I have a method which accepts function as a callback parameter. Both outer method and callback function returns promises which I collect to array, waiting for them to be resolved with Q.all.

function eval() {
    var colReadPromisses = [];

    config.mongodb.colls.forEach(function (collName) {

        var outer = mongo.readCollection(collName,
                function (jsonData) {
                    var prom = es.pushItemToES(jsonData, esIndexName, collName, i);
                    colReadPromisses.push(prom);
                });
        colReadPromisses.push(outer);
    });

    return Q.all(colReadPromisses);
}

Now, inner callback method is called many times and it takes some time to process all of them. While they are being processed, promises returned from 'readCollection' method gets 'undefined' causing 'Q.all(colReadPromisses);' to resolve.

So my two questions would be why nodejs loses track to the promises returned from 'readCollection' method and how do I avoid this?

Thanks for responses!

Upvotes: 0

Views: 103

Answers (2)

Jaromanda X
Jaromanda X

Reputation: 1

I'm assuming you want to get the results of all both readCollection and pushItemToES in the returned promise

function eval() {

    return Q.all(config.mongodb.colls.map(function (collName) {

        var pushPromisses = [mongo.readCollection(collName, function (jsonData) {
            pushPromisses.push(es.pushItemToES(jsonData, esIndexName, collName, i));
        })];

        return pushPromisses[0] // once the outer promise resolves
        .then(function() {
            return Q.all(pushPromisses); // wait for them all (including the outer)
        });

    }));
}

The returned promise when resolved, will resolve to a two-dimension array

  • [0][0] will be the result of the mongo.readCollection(colls[0])
  • [0][1..n] will be the results of each pushItemToES from readCollection(colls[0])
  • [1][0] will be the result of themongo.readCollection(colls[1])`
  • [1][1..n] will be the results of each pushItemToES from readCollection(colls[1])

and so on

if you don't need the result of mongo.readCollection in the returned promise

function eval() {

    return Q.all(config.mongodb.colls.map(function (collName) {

        var pushPromisses = [];

        return mongo.readCollection(collName, function (jsonData) {
            pushPromisses.push(es.pushItemToES(jsonData, esIndexName, collName, i));
        }).then(function() {
            return Q.all(pushPromisses);
        });

    }));
}

in this case the returned promise is still two dimensional, but with just the results of the pushItemToES

  • [0][0..n] will be the results of each pushItemToES from readCollection(colls[0])
  • [1][0..n] will be the results of each pushItemToES from readCollection(colls[1])

I can't see any way around the two dimensional array in the resolved promise - because the es.pushItemToES is not called a "known" (at least not ahead of time) number of times

Upvotes: 1

Bob  Sponge
Bob Sponge

Reputation: 4738

You must reorganize your code:

function eval() {
    // replace forEach with map
    var colReadPromisses = config.mongodb.colls.map(function (collName) {

           // return pushItemToES promises
            return new Promise(function(resolve) {
                mongo.readCollection(collName,
                    function (jsonData) {
                        resolve(es.pushItemToES(jsonData, esIndexName, collName, i));                   
                    });
            });

    });

    // colReadPromisses stores array of pushItemToES promises
    return Q.all(colReadPromisses);
}

Upvotes: 0

Related Questions