Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finally gets called immediately before promise gets fulfilled

I'm trying to execute a check once promise gets fulfilled in angularjs.

request.then(function(res){
    $ionicLoading.hide();
    deferred.resolve(res);
  }, function(res){
    $ionicLoading.hide();
    deferred.reject(res);
  })['finally'](function(res){
      alert(res)
    }
  )

But the alert is coming as 'undefined'.

  1. Is that expected or I'm doing anything wrong? I thought it'll get called only when promise gets resolved/rejected.
  2. What is the right way to achieve this?

Thanks

like image 286
Indyarocks Avatar asked Sep 04 '14 16:09

Indyarocks


3 Answers

Edit/Update ... This is not the most awesome way of doing, but a simple and straightforward way. You need to keep track of what you want to to finally alert as you go down the chain of promises (assuming you have multiple), and just store it in a variable.

var something = null;
request.then(function(response){
    $ionicLoading.hide();
    something = response;
  }, function(reason){
    $ionicLoading.hide();
    something = reason;
  }).finally(function(){ 
      alert(something);
  });

A plunker to demonstrate:

http://plnkr.co/edit/DrqeaCAYWTQ4iWY0NPeq?p=preview

like image 163
SoluableNonagon Avatar answered Nov 18 '22 19:11

SoluableNonagon


You are doing it correctly, the problem is that the value that is being passed to the finally callback is the same value returned by success or error callbacks. Since you are not returning anything, the value is undefined.

If you add the return clauses to each callback it should work:

request.then(function(res){
  $ionicLoading.hide();
  deferred.resolve(res);
  return res;
}, function(res){
  $ionicLoading.hide();
  deferred.reject(res);
  return res;
})['finally'](function(res){
    alert(res)
  }
)

Edit

It seems Angular's finally implementation is not quite prepared to pass a value to the callback. However there is another way to produce the effect you want, just replace the finally by another then:

request.then(function(res){
  $ionicLoading.hide();
  deferred.resolve(res);
  return res;
}, function(res){
  $ionicLoading.hide();
  deferred.reject(res);
  return res;
}).then(function(res){
    alert(res)
  }
)

Since the promises are executed sequentially, the final then will run lastly. And since you are not returning any other promises on the success and error callbacks, the last then will only need a success callback.

Ultimately you could also use something like this:

...)['finally'](function(){ }).then(function(res){
    alert(res)
  }
)
like image 34
bmleite Avatar answered Nov 18 '22 19:11

bmleite


The finally callback is called with no arguments. It does, however, return a promise passing the results along.

Even fixing for that, you're not returning anything in your callbacks, so nothing is being passed along. To illustrate this:

angular.module('myApp', [])
.run( function ($q) {
    var defer = $q.defer();
    defer.promise.then(
        function ( res ) { console.log('s1> '+res); },
        function ( res ) { console.log('e1> '+res); }
    )
    .then(
        function ( res ) { console.log('s2> '+res); },
        function ( res ) { console.log('e2> '+res); }
    )

    defer.reject(1);
});

Gives this:

e1> 1
s2> undefined

Notice that the second then was "successful" because the reject didn't get passed on.

Make sure that your callbacks return something. And if you want to fall to the errback in subsequent thens make sure that you return a rejection.

var defer = $q.defer();
defer.promise.then(
        function ( res ) { console.log('s1> '+res); return res; },
        function ( res ) { console.log('e1> '+res); return $q.reject(res); }
)
.then(
        function ( res ) { console.log('s2> '+res); return res; },
        function ( res ) { console.log('e2> '+res); return $q.reject(res); }
)

Putting that together gives something like this:

var defer = $q.defer();
defer.promise.then(
        function ( res ) { console.log('s1> '+res); return res; },
        function ( res ) { console.log('e1> '+res); return $q.reject(res); }
)
.then(
        function ( res ) { console.log('s2> '+res); return res; },
        function ( res ) { console.log('e2> '+res); return res; }
)
.finally (
        function ( res ) {
            console.log('f0> '+res+','+arguments.length);
        }
)
.then(
        function ( res ) { console.log('s3> '+res); return res; },
        function ( res ) { console.log('e3> '+res); return $q.reject(res); }
)

defer.reject('foo');

Resulting in:

e1> foo
e2> foo
f0> undefined,0
s3> foo

Notice that the errback in the second then returned res instead of a rejection, so the callback of the finally's then was called.

like image 4
marneborn Avatar answered Nov 18 '22 19:11

marneborn