7

I'm trying to figure out how to use promises correctly with the bluebird library. I've come across some nested promises in my code and I noticed that in the bluebird docs it reads:

if you are utilizing the full bluebird API offering, you will almost never need to resort to nesting promises in the first place.

There are many other blog posts about promises being misused and nesting is a regular anti-pattern.

loadCar(someUri) // jqXHR
    .then(function (car) {
        if (carHasFourDoors(car)) {
            loadMake(car.make)
                .then(function (make) {
                    loadModel(make.model)
                        .then(function (model) {
                            loadCarDetails(model)
                        });
                });
        }
        else if (carHasTwoDoors(car)) {
            loadModel(make.model)
                .then(function (model) {
                    loadCarDetails(model)
                });
        }
    });

All of my functions return objects. Looking at the bluebird docs, it seems like there are multiple helper methods: all(), join(), props().

So, my question is: How could I avoid the nesting if there are dependencies? Perhaps this is my misunderstanding of the asynchronous nature of promises. Could something like this work?

Promise.all(loadCar(someUri), loadMake(car.make), loadModel(make.model))
    .then(function(car, make, model) {
        // do logic
    });
Jeff
  • 2,293
  • 4
  • 26
  • 43

1 Answers1

6

You always need nesting for control structures, and usually you will need one level of nesting for the function expressions passed to then(). It's not totally avoidable, but can be reduced significantly.

In your case, you even can omit some of the function expressions and pass the functions directly.

loadCar(someUri).then(function (car) {
    if (carHasFourDoors(car)) {
        return loadMake(car.make)
    else if (carHasTwoDoors(car))
        return make; // not sure actually where you get this from
}).then(function (make) {
    return loadModel(make.model)
}).then(loadCarDetails)
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • If the call to loadMake() calls a function that eventually throws, shouldn't it resolve to a catch in my target promise? – Jeff Jun 25 '14 at 18:26
  • Since `loadMake` returns a promise, [it shouldn't `throw` anyway](http://stackoverflow.com/q/21887856/1048572), but even it it does the exception will get caught by the `then()` that executes the callback (unless you use jQuery, make sure to cast the jqXHR to a Bluebird promise) – Bergi Jun 25 '14 at 18:30
  • I am casting a jqXHR to a BB promise in my custom library. When the call fails and ends up in the catch(), I use Promise.reject(). I would think this would propagate to the catch statement in my target promise. I tried throwing instead to see if it made a difference. – Jeff Jun 25 '14 at 18:36
  • You might want to ask a new question where you post that code (including the casting, the catch, the Promise.reject and the target promise) – Bergi Jun 25 '14 at 18:39