10

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

Indyarocks
  • 643
  • 1
  • 6
  • 26
  • why are you using array notation? and not .finally() ? – SoluableNonagon Sep 04 '14 at 17:39
  • 4
    @EliteOctagon from the doc: "Because finally is a reserved word in JavaScript and reserved keywords are not supported as property names by ES3, you'll need to invoke the method like promise['finally'](callback) to make your code IE8 and Android 2.x compatible." – Manny D Sep 04 '14 at 17:57
  • I believe the `finally` callback isn't meant to take parameters because I believe in general, `finally` clauses are guaranteed to be called after some execution to allow you to clean up resources and whatnot. – Manny D Sep 04 '14 at 18:31
  • @MannyD in the same manner, you can use the alias .fin() rather than .finally() https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback , finally() is meant to take parameters, a function – SoluableNonagon Sep 05 '14 at 19:05
  • nonetheless, I think I and bmleite both address your question of why you're getting undefined and what the right way to achieve it is. You're just missing a return statement for the promises. – SoluableNonagon Sep 05 '14 at 19:09
  • 2
    Hi, could you possibly select an answer if one helped you? – SoluableNonagon Dec 12 '16 at 06:01

3 Answers3

10

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

SoluableNonagon
  • 11,541
  • 11
  • 53
  • 98
6

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)
  }
)
bmleite
  • 26,850
  • 4
  • 71
  • 46
  • 1
    This is only partially correct. It's true that the success/fail callbacks need to return something to pass to the finally call, but this code will still output `undefined`. – Manny D Sep 04 '14 at 18:18
4

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.

marneborn
  • 699
  • 3
  • 9