DomingoSL
DomingoSL

Reputation: 15484

Chaining promises with promises inside then()

How do you chain in an scenario like this?

api is a function that returns a promise after an http request. auth is a function that returns a promise after api respond, if resolves api is called for a second time, if not auth rejects.

I tried this, but not only am I going back to the callback hell, it does not work.

function api(query) {
   return new Promise(function(resolve, reject) {
     //DO SOME STUFF AND SOMETIMES resolves...
   })
}

function auth() {
   return new Promise(function(resolve, reject) {
     api("/foo").then(function(asset1) {
        api("/bar").then(function(asset2) {
           resolve(asset2);
        }).catch(function() {
           reject();
        })
     }).catch(function(error) {
        reject();
     })

   })
}

Upvotes: 22

Views: 28810

Answers (4)

Amritansh
Amritansh

Reputation: 321

A cleaner way to do it:

return myFirstPromise.then( (returnFromFirst) => {
    //Do something
    return secondPromise();
}).then( (returnFromSecond) => {
    //Do something
    return thirdPromise();
}).then( (returnFromThird) => {
    //All Done
}).catch( (e) =>{}
    console.error("SOMETHING WENT WRONG!!!");
);

Upvotes: 14

Anorflame
Anorflame

Reputation: 394

from Promises standard:

If x is a promise, adopt its state [3.4]: If x is pending, promise must remain pending until x is fulfilled or rejected. If/when x is fulfilled, fulfill promise with the same value. If/when x is rejected, reject promise with the same reason.

The next example prints 'finalVal':

let resolveP1 = null;

let p1 = new Promise(function(resolve, reject) {
    resolveP1 = resolve;
});

let p2 = new Promise(function(resolve, reject) {
    resolve(p1);
});

let p3 = p2.then(function(finalVal) {
    console.log(finalVal);
});

resolveP1('finalVal')

Upvotes: 5

Rômulo M. Farias
Rômulo M. Farias

Reputation: 1523

I think this should help you.

Just an observation: then method always return a promise based on the previous promise resolution. If the previous promise is resolved it will pass the resolved value to the next promise. Otherwise it will send the error to the catch method.

function auth () {
  /*
    Since `then` already returns a new Promise, 
    you don't need to create a new Promise.
  */
  return api('/foo').then(function (asset1) {
    return api('/bar')
  })
}

/*
  So you can call auth:
*/

auth().then(function (asset2) {
  console.log('This is my asset2:', asset2)
}).catch(function (error) {
  console.error('Error', error)
})

Upvotes: 7

Srle
Srle

Reputation: 10496

As far as i understand what you are trying to do, following code will also resolve with asset2. Besides that i guess api function is doing http request so you could benefit from using request-promise lib instead of converting callback api with new Promise thing.

function api(query) {
   return new Promise(function(resolve, reject) {
     //DO SOME STUFF AND SOMETIMES resolves...
   })
}

function auth() {
   return api("/foo")
   .then(() => api("/bar"))
}

With this caller would do something like:

auth()
.then(asset2 => ...)
.catch(err => ...)

If order of calling api is not important, like @styfle pointed out in comment, you could write it using Promise.all

function auth () {
  return Promise.all([
    api("/foo"),
    api("/bar")
  ])
}

Upvotes: 9

Related Questions