0

我有一个链式承诺,如果其中一个承诺被拒绝,我需要执行异步操作(获取翻译后的错误消息)。由于我已经获得了成功的链接承诺,我认为不可能也链接拒绝 - 我试图简单地嵌套异步调用,但我没有从deferred.reject(deferredRejection.promise);下面得到已解决的承诺。指点赞赏!

login: function(email, password) {
  var deferred = $q.defer();
  AuthService.login(email, password).then(function(response) {
    var user = {
      'accountToken': response.accountToken,
      'email': response.username,
      'onboarded': response.onboarded,
      'verified': response.verified
    };          
    return SyncStorageService.write(SyncStorageService.storageKeys.user, 
        user);  
  }, function(error) {
    // login failed
    var deferredRejection = $q.defer();
    $translate('ALERTS.LOGIN_FAILED').then(function(translatedValue) {
      deferredRejection.resolve(translatedValue);
    });
    deferred.reject(deferredRejection.promise);
  }).then(function(data) {
    deferred.resolve(data);
  }, function(error) {
    // saving data failed
    var deferredRejection = $q.defer();
    $translate('ALERTS.UNKNOWN').then(function(translatedValue) {
      deferredRejection.resolve(translatedValue);
    });
    deferred.reject(deferredRejection.promise);
  });
  return deferred.promise;
}

更新的解决方案:

根据下面的答案,我能够重写代码如下:

login: function(email, password) {
  return AuthService.login(email, password).then(function(response) {
    return {
      'accountToken': response.accountToken,
      'email': response.username,
      'onboarded': response.onboarded,
      'verified': response.verified
    };
  }).then(function(data) {
    return SyncStorageService.write(SyncStorageService.storageKeys.user, 
        data);
  });
}

笔记:

  • 两者AuthService.loginSyncStorageService.write现在都拒绝带有Error对象(例如new Error('ALERT.ERROR_MESSAGE');)的承诺,该对象会冒泡login到控制器(以前在服务级别进行翻译);
  • 调用该login方法的控制器具有.then().catch()阻塞 - 在 .catch() 上,传递Error.message的内容被翻译和显示。
4

1 回答 1

2

看起来你并没有真正链接承诺,而是使用被遗忘的承诺/延迟反模式。对您实际希望它的行为方式进行一些假设,并考虑到对 的调用$translate,然后我怀疑以下内容就是您所追求的:

login: function(email, password) {
  return AuthService.login(email, password).then(function(response) {
    return {
      'accountToken': response.accountToken,
      'email': response.username,
      'onboarded': response.onboarded,
      'verified': response.verified
    };          
  }, function() {
    return $q.reject('ALERTS.LOGIN_FAILED');
  }).then(function(user) {
    return SyncStorageService.write(SyncStorageService.storageKeys.user, user).catch(function() {
      return $q.reject('ALERTS.UNKNOWN');
    });
  }).catch(function(message) {
    return $translate(message).then(function(translatedValue) {
      return $q.reject(translatedValue);
    });
  });
}

要记住的主要事项是:

  • 如果你肯定要拒绝派生的 Promise,请$q.reject(error)从成功或错误回调中返回。

    上面的所有错误回调都是这样做的。尝试登录或保存后的那些使用翻译键作为最终将传递给最终catch回调的错误。来自的成功回调$translate也这样做以将其已解决的承诺转换为被拒绝的承诺,因此最终的 catch 回调返回一个被拒绝的承诺,因此调用代码得到一个被拒绝的承诺,并且(可能)向用户显示已翻译的错误。

  • 如果您确实想解决派生的承诺,请从成功或错误回调中返回任何不是承诺的内容。派生的 Promise 将使用该值解决。(这包括undefined如果您没有明确的返回值)。

    这是上面return {'accountToken'....在第一个回调中返回用户时所做的。

  • 如果您想推迟一个承诺的解决/拒绝,请从成功或错误回调中返回另一个承诺。然后派生的 Promise 将最终以任何其他 Promise 被解决/拒绝的方式解决或拒绝。

    这是上面返回时所做的SyncStorageService.write...,以及返回时所做的$translate(...

于 2014-10-24T07:20:12.333 回答