如何使用 $q 多重回调 AngularJs 中的一个 promise?

How to multi-callback a promise in AngularJs with $q?

我正在使用下面的代码来简化后端请求,但我没有理解如何调用成功方法或错误方法。

如何达到代码中注释的预期行为?

 
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: "Error",
                        text: data.error,
                        type: "warning"
                    });
                //HERE I WANT TO CALL .error(details)
                }
                else
                    deferred.resolve(data.result);

                        }).error(function () {
                //HERE I WANT TO CALL .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;
    });
}

按如下方式更新您的代码

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;
       });
   }

首先,我强烈建议您不要将 .success 附加到您 return 的承诺上。这不是 Promises/A-compliant,它与 .then 的细微差别(由 $http 实现)会引起很多混淆。只是 return 一个纯粹的承诺。

除此之外,还有几点需要注意:

1) 你不需要另一个 $q.deferdeferred.resolve() - 只需链接到 $http 和 [= 的原始承诺18=] 结果承诺。 (参见 deferred anti-pattern

2) 拒绝一个 promise - 也就是说,触发 .catch(不是 .error - 见上文关于细微差别) - 你应该 return $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"
        });
    }
  };
})

然后,正如我上面所说,像使用 promises 一样使用 .then/.catch

$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;
        });
}