0

A Bluebird Promise returns an object that contains two arrays of objects, cars and contracts. Then, I want to iterate over the cars, call an asynchronous function and, based on the returned value, make some changes to the second array and return the initial result object with these changes. I can't figure out how to do this with promises. Or with async, for that matter. I feel like they should be nested promises, but i can;t get it to work at all.

the version with promises:

somePromise().then(function (result) {

    Promise.each(result.cars, function (car) {
        makeAsyncCall(car.id, function (err, resultArray) {
            if (err) {
                throw new Error();
            }

            result.contracts.forEach(function (contract) {
                if (resultArray.indexOf(contract.id) > -1) {
                    contract.car = car.id;
                }
            });
        });

    }).then(function (eachResult) {
        //eachResult is result.firstArray, which is not interesting.
        return result;
    });

}).then(function (result)) {
    //this gets called before my promise.each gets executed??
}

Can anyone give me a hint as to where my mistake is?

glasspill
  • 1,290
  • 4
  • 21
  • 36
  • 2
    Shouldn't you return the promises, so that they can be chained? – thefourtheye Apr 10 '15 at 16:23
  • 1
    You are mixing promises, callbacks (makeAsyncCall) and synchronous code (forEach), which is just asking for trouble. You should convert your `makeAsyncCall` to return a promise as well so it can be chained. This can be done by using `Promise.defer()` or bluebird has a function to do it for you called `promisify`: https://github.com/petkaantonov/bluebird/blob/master/API.md#promisepromisifyfunction-nodefunction--dynamic-receiver---function You'll also want to `Promise.each` your `contracts` as well, again, adding to the promise chain. – M. Adam Kendall Apr 10 '15 at 16:33
  • @thefourtheye you are right. That fixed it. – glasspill Apr 10 '15 at 16:34
  • @M.AdamKendall you're also right. i should do that. it's messy. – glasspill Apr 10 '15 at 16:36

1 Answers1

1

Have a look at my rules of thumb for promise development. The two specific points that apply to your code are:

  • promisify your async callback-taking functions before using them, specifically

    var makeCall = Promise.promisify(makeAsyncCall);
    
  • always return promises from your functions that do asynchronous things. This is especially true for callbacks, like the function() { Promise.each(…).then(…) } and the function() { makeAsyncCall(…) }.

With those, you should get to the following:

somePromise().then(function(result) {
    return Promise.each(result.cars, function(car) {
        return makeCall(car.id).then(function(resultArray) {
            // a lookup structure of contracts by id could make this more efficient
            result.contracts.forEach(function (contract) {
                if (resultArray.indexOf(contract.id) > -1)
                    contract.car = car.id;
            });
        });
    }).return(result);
}).…
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375