dooburt
dooburt

Reputation: 3060

Performing asynchronous operation within bluebird promise

So, I've been beating this one about for a few days and I'm stumped as to what is the best way to solve it. I am using Waterline/dogwater with HAPI and trying to do something broadly like so:-

wardrobe.find({WardrobeId: 5}).then(function(clothes) {
    //got my clothes in my wardrobe.
    clothes.find({Type: 'trousers'},{Kind: 'nice ones'}).then(function(trousers) {
        //got my nice trousers
        _.each(trousers, function(trouser) {
            //logic to see if these are my pink trousers
            console.log('color?', trouser.color);
        });
        console.log('ding');
    });
});

The trouble I have is the code will always ding before it outputs the trouser colors. This is because, as much as I understand it, _.each will make the code go async. I tried to introduce Promises (bluebird), but without luck. I even looked at generators (Co), but my node version is fixed at pre v0.11.

I'd like to perform some database look-ups within the _.each, return these results (if any) to the trouser object, which can then be returned:-

wardrobe.find({WardrobeId: 5}).then(function(clothes) {
    //got my clothes in my wardrobe.
    clothes.find({Type: 'trousers'},{Kind: 'nice ones'}).then(function(trousers) {
        //got my nice trousers
        _.each(trousers, function(trouser) {
            //logic to see if these are my pink trousers
            db.colors.find({Color: trouser.color}).then(function(color) {
                //color here?
            });
        });
        console.log('ding');
    });
});

What is the best way to do this as efficiently as possible?

Help is appreciated. Happy to return here and focus the question where needed.

Upvotes: 1

Views: 432

Answers (1)

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276296

Well _.each has nothing to do with asynchronicity. It's just a underscore/lodash way to do trousers.forEach(...).

Your issue is with the db.colors.find method which performs an async operation. You can chain the methods if you want them to execute sequentially as such:

wardrobe.find({WardrobeId: 5}).then(function(clothes) {
    //got my clothes in my wardrobe.
    clothes.find({Type: 'trousers'},{Kind: 'nice ones'}).then(function(trousers) {
        //got my nice trousers
        var p = Promise.resolve();
        _.each(trousers, function(trouser) {
            //logic to see if these are my pink trousers
            p = p.then(function() {
                return db.colors.find({Color: trouser.color})
                    .then(function(color) {
                        // color here, they'll execute one by one
                    });
            });
        });
        p.then(function(){ 
            console.log('ding, this is the last one');
        });
    });
});

Or, if you want them to all happen in concurrently and not to wait for the previous one:

wardrobe.find({WardrobeId: 5}).then(function(clothes) {
    //got my clothes in my wardrobe.
    clothes.find({Type: 'trousers'},{Kind: 'nice ones'}).then(function(trousers) {
        //got my nice trousers
        Promise.map(trousers, function(trouser) {
            return db.colors.find({Color: trouser.color});
        }).map(function(color){
            console.log("color", color);
        }).then(function(){ 
            console.log('ding, this is the last one');
        });
    });
});

Upvotes: 5

Related Questions