5

I want to build a nested $http.get, after the first succeed, then request the second.

then i came out with something like this:

$http.get('/xxx').then(function(response){
    $http.get('/yyy').then(function(response){
        //do something
    })
});

But i want to return a Promise after all, so that i can organise my code properly. Obviously the code above doesn't meet my need.

Then i did a lot research with $q.all(), but actually with $q.all, the second request doesn't wait for the first, it will send second request even if the first request doesn't successfully response.

After that i found a solution, which works like a charm in my case:

var promise = $http.get('/xxx').then(function(response1){
    return $http.get('/yyy').then(function(response2) {
        return response2.data;
    });;
});     
return promise;

But i don't understand why would it work???

In the success function of first promise($http.get), it returns the second promise as the parameter of the function for then().

but if i call

promise.then(function(data){
    console.log(data);
});

i found the data printed here is response2.data, how could it be possible? Shouldn't it be the Promise Object of the second $http???

Demonbane
  • 339
  • 3
  • 15
  • possible duplicate of [Aren't promises just callbacks?](http://stackoverflow.com/a/22562045/1048572) (spoiler: they're not) – Bergi Jul 02 '15 at 19:55
  • @Bergi you are right. i just checked the question and found they are quite similar. but how could i mark it as duplicated and link the question you mentioned? – Demonbane Jul 02 '15 at 20:23
  • You could have [flagged your question](http://stackoverflow.com/help/privileges/flag-posts), as you can't yet [vote to close](http://stackoverflow.com/help/privileges/close-questions) [your questions](http://stackoverflow.com/help/privileges/view-close-votes). Alternatively, you might have accepted a duplicate suggestion by another community member. I didn't make one (I only commented) as it would've closed the question immediately - as I now have done. – Bergi Jul 02 '15 at 20:50

2 Answers2

12

When you return a promise from a promise .then(…) callback, the promise library will automatically wait for the inner promise to resolve, and will then resolve the returned promise with that value.

In other words, if you make a promise of a promise, you will get its inner value back.

This is part of the beauty of promises; you can reduce nesting by taking advantage of this feature and chaining your promises:

var promise = $http.get('/xxx').then(function(response1) {
    return $http.get('/yyy');
}).then(function(response2) {
    return response2.data;
});

For more details, see my blog.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Thanks! Is it the principle for general Promise (for example Promise in ES6), or it's just an implementation of angular's $q ? – Demonbane Jul 02 '15 at 19:47
  • @Demonbane: This is explicitly stated in the spec. Read https://promisesaplus.com/ – SLaks Jul 02 '15 at 19:47
0

The first attempt doesn't work because you're not returning the promise returned by the inner http call. Instead it is returning a derived promise from the first then. The derived promise is resolved with a value of undefined.

Some more info here: http://www.syntaxsuccess.com/viewarticle/angular-promise-chaining-explained

TGH
  • 38,769
  • 12
  • 102
  • 135