如何在AngularJs中使用$q实现Promise的多重回调?

3
我使用下面的代码简化后端请求,但我不知道如何调用success方法或error方法。
我该如何实现代码中所注释的期望行为?
 
app.factory('REST', function ($http, $q, sweetAlert) {
return { load: function (module, action, data) { var deferred = $q.defer(); var promise = deferred.promise; $http .post('/api/'+module+'.php?action='+action, data) .success(function (data) {
if(data.error) { sweetAlert.swal({ title: "错误", text: data.error, type: "warning" }); //在此处我想调用.error(details) } else deferred.resolve(data.result);
}).error(function () { //在此处我想调用.error(details) });
promise.success = function(fn) { promise.then(fn); return promise; }
return promise; } }; });
这是使用上述代码的代码:
$scope.login = function () {
    $scope.loading = true;
    var payload = {'credentials': $scope.logindata};
    REST.load('access', 'login', payload).success(function(data) {
        if(data.redirect)
            $state.go(data.redirect);
        $scope.loading = false;
    }).error(function(data) { //THIS SHOULD BE CALLED
        $scope.loading = false;
    });
}

常规的 Promise 没有 success()/error() 函数。它们有 then() 和 catch() 函数。这些是客户端代码应该调用的函数。请阅读 http://blog.ninja-squad.com/2015/05/28/angularjs-promises/。 - JB Nizet
你的意思是你想调用.reject()而不是.error()吗? - Bergi
2个回答

5

首先,我强烈不建议您将.success附加到返回的Promise上。这不符合Promises/A标准,并且它与$http实现的.then有微妙的差别,容易引起混淆。请返回纯粹的Promise。

除此之外,还有一些需要注意的地方:

1) 您不需要另一个$q.deferdeferred.resolve() - 只需链接到$http的原始Promise并return结果即可。(参见deferred anti-pattern

2) 要拒绝Promise(即触发.catch,而非.error - 请参见上文关于微妙差别的说明),您应该返回$q.reject()

以上所有内容产生以下结果:

app.factory('REST', function($http, $q, sweetAlert){
  return {
    load: function(module, action, data) {
      // this "return" returns the promise of $http.then
      return $http.post('/api/' + module + '.php?action=' + action, data)
        .then(function(response) {
          var data = response.data; // .then gets a response, unlike $http.success

          if (data.error) {
            sweetAlert.swal({
              title: "Error",
              text: data.error,
              type: "warning"
            });

            //HERE I WANT TO CALL .error(details)

            return $q.reject(data.error);
          }

          return data.result; // what you would have "resolved"
        });
    }
  };
})

然后,如上所述,使用 .then/.catch,就像处理 promises 一样:

$scope.login = function () {
    $scope.loading = true;
    var payload = {'credentials': $scope.logindata};
    REST.load('access', 'login', payload)
        .then(function(data) {
          if(data.redirect)
             $state.go(data.redirect);
          $scope.loading = false;
        })
        .catch(function(error) {
          $scope.loading = false;
        });
}

1
更新您的代码如下:
app.factory('REST', function ($http, $q, sweetAlert) {
   return {
       load: function (module, action, data) {
              var deferred = $q.defer();                  
                  $http.post('/api/'+module+'.php?action='+action, data)
                          .success(function (data) {
                              if(data.error)
                              {
                                  sweetAlert.swal({
                                      title: "Error",
                                      text: data.error,
                                      type: "warning"
                                  });     
                                 //HERE I WANT TO CALL .error(details)                                
                                 deferred.reject(data.error);
                              }
                              else{
                                deferred.resolve(data.result);
                              }

                         })
                         .error(function (error) {
                              //HERE I WANT TO CALL .error(details)
                              deferred.reject(error);   
                          });

               return defferred.promise;
          }
   };
});

为您的控制器

 $scope.login = function () {
     $scope.loading = true;
     var payload = {'credentials': $scope.logindata};
     REST.load('access', 'login', payload).then(
       function(data) {
         if(data.redirect)
             $state.go(data.redirect);
             $scope.loading = false;
       },
       function(error) {
          $scope.loading = false;
       });
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接