最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Stopping an AngularJS promise chain - Stack Overflow

programmeradmin4浏览0评论

I'm trying to figure out a good way to say "Do all of these things, but bail in the case that any of them fails"

What I have right now:

var defer = $q.defer();

this
    .load( thingy ) // returns a promise

    .then( this.doSomethingA.bind( this ) )
    .then( this.doSomethingB.bind( this ) )
    .then( this.doSomethingC.bind( this ) )
    .then( this.doSomethingD.bind( this ) )

    .then( function(){
        defer.resolve( this );
    } );
    ;

return defer.promise;

What I ultimately want is to somehow catch any error on that chain so I can pass it on to the defer promise above. I don't particularly care if the syntax is kept similar to what I have above.

Or even if anyone can just tell me how to stop the above chain.

I'm trying to figure out a good way to say "Do all of these things, but bail in the case that any of them fails"

What I have right now:

var defer = $q.defer();

this
    .load( thingy ) // returns a promise

    .then( this.doSomethingA.bind( this ) )
    .then( this.doSomethingB.bind( this ) )
    .then( this.doSomethingC.bind( this ) )
    .then( this.doSomethingD.bind( this ) )

    .then( function(){
        defer.resolve( this );
    } );
    ;

return defer.promise;

What I ultimately want is to somehow catch any error on that chain so I can pass it on to the defer promise above. I don't particularly care if the syntax is kept similar to what I have above.

Or even if anyone can just tell me how to stop the above chain.

Share Improve this question asked May 30, 2013 at 23:17 user578895user578895 3
  • 1 @user2246674 -- rejecting it doesn't seem to stop the chain though, the next one just continues – user578895 Commented May 30, 2013 at 23:22
  • 1 Don't know what I was thinking .. – user2246674 Commented May 30, 2013 at 23:30
  • 2 This is a horrid example of the deferred antipattern! Screw that defer, just return the this.load(…).then(A).then(B).then(C).then(D); chain! – Bergi Commented Jul 1, 2015 at 17:58
Add a comment  | 

6 Answers 6

Reset to default 7

You can stop angularjs chain by returning rejected promise inside any then callback.

load()
.then(doA)
.then(doB)
.then(doC)
.then(doD);

where doA, doB, doC, doD can have logic like this:

var doA = function() {
    if(shouldFail) {
        return $q.reject();
    }
}

I just stumbled across this and realized all these answers are terribly outdated. Here is the proper way to handle this for anyone that happens to find this post.

// Older code
return this.load(thing)
  .then(this.doA, $q.reject)
  .then(this.doB, $q.reject)
  .then(this.doC, $q.reject)
  .then(this.doD, $q.reject)
  .then(null, $q.reject);


// Updated code
// Returns the final promise with the success handlers and a unified error handler
return this.load(thing)
  .then(this.doA)
  .then(this.doB)
  .then(this.doC)
  .then(this.doD)
  .catch(this.handleErrors); // Alternatively, this can be left off if you just need to reject the promise since the promise is already rejected.
  // `.catch` is an alias for `.then(null, this.handleErrors);`

You should be able to do that same thing by:

var defer = $q.defer();

this
    .load( thingy ) // returns a promise

    .then( this.doSomethingA.bind( this ), $q.reject )
    .then( this.doSomethingB.bind( this ), $q.reject )
    .then( this.doSomethingC.bind( this ), $q.reject )
    .then( this.doSomethingD.bind( this ), $q.reject )

    .then( defer.resolve.bind( defer, this ), defer.reject.bind( defer ) );
    ;

return defer.promise;

The best way to handle this and also to catch the problem is the .catch block. Inside any .then block that you wanna kill the promise chain, yes use:

 return $q.reject();

However extend it like so...

 return $q.reject(new Error('Error Message Here'));

Now in the catch method you will have this

 .catch(function(err) {
     console.log(err); //This will log the above 'Error Message Here'
 });

Now we throw and handle the promise error correctly in the fashion promise failures were meant to be handled.

Okay, this works but I don't like it... Awaiting something better :)

It just seems dirty to create a promise for the sole sake of immediately rejecting it

myApp
    .factory( 'chainReject', [ '$q', function( $q ){
        return function( err ){
            var defer = $q.defer();
            defer.reject( err );

            return defer.promise;
        }
    } ] );

...

var defer = $q.defer();

this
    .load( thingy ) // returns a promise

    .then( this.doSomethingA.bind( this ), chainReject )
    .then( this.doSomethingB.bind( this ), chainReject )
    .then( this.doSomethingC.bind( this ), chainReject )
    .then( this.doSomethingD.bind( this ), chainReject )

    .then( defer.resolve.bind( defer, this ), defer.reject.bind( defer ) );
    ;

return defer.promise;

Looks like this use case has been anticipated and addressed with the use of $q.reject(reason)

发布评论

评论列表(0)

  1. 暂无评论