当需要处理错误并继续使用Promise流时,更好地承诺

时间:2014-05-04 17:33:16

标签: node.js promise bluebird

我需要在我的函数中使用跟随逻辑:

  1. 使用护照登录facebook,我调用该方法检索具有facebook id的用户。
  2. 如果用户存在,完成!
  3. 否则我调用该方法来检索具有该电子邮件的用户。
  4. 如果用户存在,我需要使用facebook ID更新用户并完成!
  5. 否则,如果用户不存在,我需要使用电子邮件和Facebook ID创建他的帐户。
  6. 例如,在java中,它会是这样的:

    try {
      User user = userService.findByFacebookAccount(id);
      if(user != null) {
        done(user);
      } else {
        user = userService.findByEmail(email);
        if(user != null) {
          user.setFacebookAccount(id);
          if(userService.update(user)) {
            done(user); // Update with success
          } else {
            throws new Exception();
          }
        } else {
          user = userService.createByFacebookAccount(name, email, facebook_id);
          if(user != null) {
            done(user);
          } else {
            throws new Exception();
          }
        }
      }
    } catch(Exception e) {
      done(e);
    }
    

    我如何组织与Promises有关的事情? 我使用蓝鸟承诺如下:

    function(accessToken, refreshToken, profile, done) {
      var profileInfos = profile._json;
      userService.findByFacebookAccount(profileInfos.id).then(function(user) {
        done(null, user);                                  
      }).error(function(e) {
        return userService.findByEmail(profileInfos.email);
      }).then(function(user) {            
        user.set('facebook_account', profileInfos.id);
        return userService.update(user, ['facebook_account']);
      }).then(function(user) {
        done(null, user);
      }).error(function(e) {        
        return userService.createByFacebookAccount(profileInfos.name, profileInfos.gender, profileInfos.username, profileInfos.email, profileInfos.id);
      }).then(function(user) {
        done(null, user);                    
      }).catch(function(e) {
        done(null);
      });
    }
    

    我认为这是错误的,因为当"返回userService.update(用户,[' facebook_account']);"被拒绝我需要捕获错误并返回错误并且不创建用户。

    从同步逻辑转换为承诺的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

不要混合使用promises和callback,除非你想制作一个回调api,但想在内部使用promises(在这种情况下使用.nodeify)。也不要吞下错误并强迫用户检查返回值。

function doIt(accessToken, refreshToken, profile, done) {
  var profileInfos = profile._json;
  return userService.findByFacebookAccount(profileInfos.id).then(function(user) {
    if (user != null) {
      return user;
    }
    return userService.findByEmail(profileInfos.email).then(function(user) {
      if (user != null) {
        user.setFacebookAccount(id))
        return userService.update(user).then(function(updated) {
          // userService should actually just throw the error in the first place and not
          // swallow it and return false, which is making code much uglier than it needs to be here
          if (!updated) throw new Error();
          return user;
        });
      } else {
        return userService.createByFacebookAccount(name, email, facebook_id).then(function(user) {
          if (user != null) return user;
          throw new Error();
        })
      }
    })                                
  }).nodeify(done);
}

用法是:

doIt(...)
.then(function(user) {

})
.catch(function(error){

});

由于我们使用了.nodeify(),因此也支持回调接口:

doIt(..., function(err, user) {

});

如果服务使用异常而不是在出现错误时返回null / false,则可能会稍微清晰一些:

function doIt(accessToken, refreshToken, profile, done) {
  var profileInfos = profile._json;
  return userService.findByFacebookAccount(profileInfos.id).then(function(user) {
    if (user != null) {
      return user;
    }
    return userService.findByEmail(profileInfos.email).then(function(user) {
      if (user != null) {
        user.setFacebookAccount(id))
        return userService.update(user).thenReturn(user);
      } else {
        return userService.createByFacebookAccount(name, email, facebook_id)
      }
    })                                
  }).nodeify(done);
}