How to get the value of the first promise that succeeds in a chain of promises

I'm looking for a way to return a promise only if another promise fails .

How can I do that?

The promises that I have look like this ( of course I've remove non-related code ) :

getUserByUsername = function(username) {
    return promise(function(resolve, reject) {
       user = userModel.getByUsername(username);
       if ( user ) { resolve(user); } else { reject("user not found"); }
    });
};

getUserByEmail = function(email) {
    return promise(function(resolve, reject) {
       user = userModel.getByEmail(email);
       if ( user ) { resolve(user); } else { reject("user not found"); }
    });
};

checkPassword = function(user, password) {
    return promise(function(resolve, reject) {
       if ( user.isValidPassword(password) ) { resolve() } else { reject("password mismatch"); }
    });
};

And I want to combine them in the following sequence

  • Call getUserByUsername and if rejects then call getUserByEmail
  • Return the value of whoever resolves from the two promises above OR if both promises fail reject the whole chain.
  • Call checkPassword with the value and if it rejects, reject the whole chain
  • So far I have done this and it seems to work. ( I'm using when.js btw )

    getUserByUsername(usernameOrEmail)
    .then( 
        function(user) { return user; }, 
        function() { return getUserByEmail(usernameOrEmail) } 
    )
    .then( function(user) { return checkPassword(user, password) } )
    .done( 
        function() { console.log('success'); }, 
        function(err) { console.log('failure', err) }
    );
    

    So this code works but I'm pretty sure there should be more elegant way of doing this ( I think my code looks more like a hack ).


    What about something like:

     getUserByUsername(usernameOrEmail).
     catch(getUserByEmail.bind(null, usernameOrEmail)).
     then(function(user){
         if(!isValidPassword(user, password)) throw new Error("Invalid Password");
     }).then(function(){
         // success
     }, function(){
        //fail
     });
    

    Key things:

  • You can throw to reject promises and return to continue chains. There is little use to the promise constructor.
  • You can omit the first parameter in .then by doing .then(null, function(){... however it is even simpler to use .catch which is an alias for that. More generally .then ignores parameters that are not functions.
  • Rejections and return values propagate, if you don't handle a rejections through a .catch (or a second argument for .then ) it will simply move across the chain until you do. The same goes for return values - this is why the first two lines here encompass:
  • Try to get the user by username
  • If that fails, try by email.
  • In general what you describe is very common with promises and parallels to exceptions in synchronous code very well. It's important to learn how to do this sort of thing effectively.

    链接地址: http://www.djcxy.com/p/55448.html

    上一篇: 我如何判断对象是否是Promise?

    下一篇: 如何获得成功实现一系列承诺的第一个承诺的价值