118

$http在 AngularJs 中使用,我不确定如何使用返回的承诺和处理错误。

我有这个代码:

$http
    .get(url)
    .success(function(data) {
        // Handle data
    })
    .error(function(data, status) {
        // Handle HTTP error
    })
    .finally(function() {
        // Execute logic independent of success/error
    })
    .catch(function(error) {
        // Catch and handle exceptions from success/error/finally functions
    });

这是一个好方法,还是有更简单的方法?

4

6 回答 6

106

Promise 是对语句的抽象,它允许我们用异步代码同步地表达自己。它们代表一次性任务的执行。

它们还提供异常处理,就像普通代码一样,您可以从 Promise 中返回,也可以抛出异常。

你想要的同步代码是:

try{
  try{
      var res = $http.getSync("url");
      res = someProcessingOf(res);
  } catch (e) {
      console.log("Got an error!",e);
      throw e; // rethrow to not marked as handled
  }
  // do more stuff with res
} catch (e){
     // handle errors in processing or in error.
}

承诺的版本非常相似:

$http.get("url").
then(someProcessingOf).
catch(function(e){
   console.log("got an error in initial processing",e);
   throw e; // rethrow to not marked as handled, 
            // in $q it's better to `return $q.reject(e)` here
}).then(function(res){
    // do more stuff
}).catch(function(e){
    // handle errors in processing or in error.
});
于 2014-05-09T08:32:12.580 回答
44

忘记使用successerror方法。

这两种方法在 Angular 1.4 中都已弃用。基本上,弃用的原因是它们不是可链接友好的,可以这么说。

通过以下示例,我将尝试说明我的意思success以及error适合链式。假设我们调用一个 API,它返回一个带有地址的用户对象:

用户对象:

{name: 'Igor', address: 'San Francisco'}

调用 API:

$http.get('/user')
    .success(function (user) {
        return user.address;   <---  
    })                            |  // you might expect that 'obj' is equal to the
    .then(function (obj) {   ------  // address of the user, but it is NOT

        console.log(obj); // -> {name: 'Igor', address: 'San Francisco'}
    });
};

发生了什么?

因为successand errorreturn原来的 promise,也就是返回的$http.get那个,所以传递给回调的对象then就是整个用户对象,也就是说和前面success回调的输入是一样的。

如果我们链接了两个then,这将不那么令人困惑:

$http.get('/user')
    .then(function (user) {
        return user.address;  
    })
    .then(function (obj) {  
        console.log(obj); // -> 'San Francisco'
    });
};
于 2015-10-22T17:30:39.597 回答
39

我认为前面的答案是正确的,但这是另一个例子(只是一个 fyi,success() 和 error() 根据 AngularJS Main page已被弃用:

$http
    .get('http://someendpoint/maybe/returns/JSON')
    .then(function(response) {
        return response.data;
    }).catch(function(e) {
        console.log('Error: ', e);
        throw e;
    }).finally(function() {
        console.log('This finally block');
    });
于 2015-09-03T05:13:13.637 回答
11

您在寻找什么类型的粒度?您通常可以通过:

$http.get(url).then(
  //success function
  function(results) {
    //do something w/results.data
  },
  //error function
  function(err) {
    //handle error
  }
);

我发现在链接多个 Promise 时,“finally”和“catch”会更好。

于 2014-05-09T07:58:17.447 回答
5

在 Angular $http 的情况下,success() 和 error() 函数将解包响应对象,所以回调签名就像 $http(...).success(function(data, status, headers, config))

对于 then(),您可能会处理原始响应对象。比如张贴在 AngularJS $http API 文档中

$http({
        url: $scope.url,
        method: $scope.method,
        cache: $templateCache
    })
    .success(function(data, status) {
        $scope.status = status;
        $scope.data = data;
    })
    .error(function(data, status) {
        $scope.data = data || 'Request failed';
        $scope.status = status;
    });

最后一个 .catch(...) 将不需要,除非在之前的承诺链中抛出了新的错误。

于 2015-01-15T20:57:44.113 回答
-3

我这样做就像 Bradley Braithwaite 在他的博客中建议的那样:

app
    .factory('searchService', ['$q', '$http', function($q, $http) {
        var service = {};

        service.search = function search(query) {
            // We make use of Angular's $q library to create the deferred instance
            var deferred = $q.defer();

            $http
                .get('http://localhost/v1?=q' + query)
                .success(function(data) {
                    // The promise is resolved once the HTTP call is successful.
                    deferred.resolve(data);
                })
                .error(function(reason) {
                    // The promise is rejected if there is an error with the HTTP call.
                    deferred.reject(reason);
                });

            // The promise is returned to the caller
            return deferred.promise;
        };

        return service;
    }])
    .controller('SearchController', ['$scope', 'searchService', function($scope, searchService) {
        // The search service returns a promise API
        searchService
            .search($scope.query)
            .then(function(data) {
                // This is set when the promise is resolved.
                $scope.results = data;
            })
            .catch(function(reason) {
                // This is set in the event of an error.
                $scope.error = 'There has been an error: ' + reason;
            });
    }])

关键点:

  • resolve 函数链接到我们控制器中的 .then 函数,即一切都很好,所以我们可以信守承诺并解决它。

  • 拒绝函数链接到我们控制器中的 .catch 函数,即出现了问题,因此我们无法兑现承诺并需要拒绝它。

它非常稳定和安全,如果您有其他条件拒绝承诺,您可以随时在成功函数中过滤您的数据并deferred.reject(anotherReason)以拒绝的原因进行调用。

正如 Ryan Vice 在评论中所建议的那样,这可能不会被视为有用,除非您对响应稍作调整,可以这么说。

因为successerror自 1.4 起已弃用,也许最好使用常规的 Promise 方法thencatch在这些方法中转换响应并返回转换后的响应的 Promise。

我展示了两种方法和第三种中间方法的相同示例:

successerror方法(successerror返回一个HTTP响应的承诺,所以我们需要帮助$q返回一个数据的承诺):

function search(query) {
  // We make use of Angular's $q library to create the deferred instance
  var deferred = $q.defer();

  $http.get('http://localhost/v1?=q' + query)
  .success(function(data,status) {
    // The promise is resolved once the HTTP call is successful.
    deferred.resolve(data);              
  })

  .error(function(reason,status) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.error){
      deferred.reject({text:reason.error, status:status});
    }else{
      //if we don't get any answers the proxy/api will probably be down
      deferred.reject({text:'whatever', status:500});
    }
  });

  // The promise is returned to the caller
  return deferred.promise;
};

thencatch方法(这有点难以测试,因为抛出):

function search(query) {

  var promise=$http.get('http://localhost/v1?=q' + query)

  .then(function (response) {
    // The promise is resolved once the HTTP call is successful.
    return response.data;
  },function(reason) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.statusText){
      throw reason;
    }else{
      //if we don't get any answers the proxy/api will probably be down
      throw {statusText:'Call error', status:500};
    }

  });

  return promise;
}

虽然有一个中途解决方案(这样你可以避免throw并且无论如何你可能需要使用它$q来模拟测试中的承诺行为):

function search(query) {
  // We make use of Angular's $q library to create the deferred instance
  var deferred = $q.defer();

  $http.get('http://localhost/v1?=q' + query)

  .then(function (response) {
    // The promise is resolved once the HTTP call is successful.
    deferred.resolve(response.data);
  },function(reason) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.statusText){
      deferred.reject(reason);
    }else{
      //if we don't get any answers the proxy/api will probably be down
      deferred.reject({statusText:'Call error', status:500});
    }

  });

  // The promise is returned to the caller
  return deferred.promise;
}

欢迎任何形式的评论或更正。

于 2016-06-13T09:33:43.430 回答