Daniel Fischer Daniel Fischer - 7 months ago 11
Javascript Question

How do I flatten a nested promise dependency?

I'm using mondora/asteroid through a node app to use Meteor DDP via a promise pattern.

I have the following code I am rewriting from callback style, into a promise style, but am stuck on how to flatten it.

asteroid.call('Pony.search', { params })
.then(res => {
if (res.length === 1) {
// something
asteroid.call('Pony.finish', { params })
// this part feels wrong
.then(res => {
// something else
});
} else {
// nope
}
})
.catch(err => {
console.error(err);
});


There is a second
asteroid.call
&
then
inside the first promise response which is a promise. This part feels wrong, like it should be flat and not nested but I'm not sure how to get there.

edit:

Ended up using something like this (still not decided on whether to have the first then check for
if length === 1
and potentially immediately reject it. Anyone know what is best practice on that?

asteroid.call('Pony.search', { params })
.then(res => res.length === 1 ? res : Promise.reject())
.then(res => asteroid.call('Pony.finish', { res[0].something }))
.then(res => {
// do something
})
.catch(err => {
// handle the no found
console.error(err);
});

Answer

Instead of nesting callbacks, chain promises together with .then()

A note:

I'm not sure what Promise library you are using, but the idea is to return a rejected promise from the first .then() if there is an error, otherwise you return a successful promise. The promise library will then handle the error handling for you, going to the catch block if there is a rejected promise.

asteroid.call('Pony.search', { params })
  .then(res => {
    res.length === 1 ? return asteroid.call('Pony.finish', { params }) : Promise.reject();
  })
  .then(res => {
    //do stuff here
  })
  .catch(err => {
    console.error(err);
  });

edit:

The only issue is when you need to access both of the return values from the promises at the same time. When you flatten out a promise chain you lose access to the results from the previous promises.

You have a few options:

  1. If you don't need the previous result then flatten out the promise chain like I did here
  2. If you do need the previous value

    2a. And you don't care about the ordering of execution then use Promise.all([promise1, promise2])

    2b. And you do care about the ordering of the execution then you must use nested promises like you originally did.