akaphenom
akaphenom

Reputation: 6888

how to map an array of objects into an array of Q promises

I cannot seem to get my head around this. I have a list of positions, which I want to turn into an array of promises, which I then want to collect. It is not working, positionPromises results in an array of nulls (e.g. [ null, null ])

var positionPromises  = _.map(positions, function(position) {

    var newPosition = Position({
        'weight': 1
        ,'ideaId': idea.id
    })  

    var promise = null
    Q.all([
                    // asynchronous sets (each does a db lookup)
        newPosition.setDirectionByName(position.direction)
        , newPosition.setSecurityByTicker(position.ticker) 
    ]).then(function(noop) {
        // the position has it's data, invoke save which also returns a promise
        promise = Position.qCreate(newPosition)
    }).done()
    return promise

    console.log("NEVER GET HERE @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
}) // _.map

console.log(positionPromises)
positionPromises.reduce(function(noop, positionPromise){
    console.log('Reduce iteration')
    positionPromise.then(function(position) {
         console.log('THEN')
    })
})

My Solution

From the answers below, this is what I am going with...

the reduce in the above attempt was meant t o be the point where I associate the position back with the idea, prior to returning it to the UI. BUT since I am not accumulating anything, ALL works (probably better):

var positionPromises = _.map(positions, function(position) {

    var newPosition = Position({
        'weight': 1
        ,'ideaId': idea.id
    })  

    return Q.all([
            newPosition.setDirectionByName(position.direction)
            , newPosition.setSecurityByTicker(position.ticker) 
        ]).then(function(noop) {
            //newPosition.setIdea(idea)
            return Position.qCreate(newPosition)
        })
}) // _.map

Q.all(positionPromises).then(function(positions){
    console.log('RESULTS of POSITION Promises')
    idea.positions = positions

    res.send(idea)

})

Upvotes: 1

Views: 422

Answers (2)

Bergi
Bergi

Reputation: 664620

var promise = null
Q.all(…)
return promise

You are returning null here from the function. All assignments to the promise variable are done in asynchronous callbacks, which will occur after the mapping function has returned.

What you need to do instead is using then for chaining: Compute both setDirectionByName and setSecurityByTicker, then when both (all) are done qCreate a promise, and then yield the value of that promise:

var positionPromises  = _.map(positions, function(position) {
    var newPosition = Position({
        'weight': 1,
        'ideaId': idea.id
    });
    return Q.all([
        newPosition.setDirectionByName(position.direction),
        newPosition.setSecurityByTicker(position.ticker) 
    ]).then(function() {
        return Position.qCreate(newPosition);
    });
})

Upvotes: 2

Mehran Hatami
Mehran Hatami

Reputation: 12961

when you do:

...).then(function(noop) {
    // the position has it's data, invoke save which also returns a promise
    promise = Position.qCreate(newPosition)
});

it doesn't get called at the time, because it is a async call, so you get nulls array.

Upvotes: 0

Related Questions