【问题标题】:Using the $q service with angular将 $q 服务与 angular 一起使用
【发布时间】:2016-07-21 19:21:21
【问题描述】:

如果你想创建一个只需要通过 http 调用一个 API 的服务,我仍然无法理解使用 $q 服务的作用,(它到底会添加什么),在这种情况下我不知道为什么我不应该只执行以下操作(不使用 $q):

this.getMovie = function(movie) {
  return $http.get('/api/v1/movies/' + movie)
    .then(
    function(response) {
      return {
        title: response.data.title,
        cost: response.data.price
      });
    },
    function(httpError) {
      // translate the error
      throw httpError.status + " : " +
        httpError.data;
    });
};

【问题讨论】:

    标签: angularjs angular-promise angularjs-http


    【解决方案1】:

    非常好的问题,只有极少数人欣赏答案。

    考虑一下:

    this.getMovie = function(movie) {
      return $http.get('/api/v1/movies/' + movie);
    };
    

    伟大的代码,但这些规则适用:

    $http 将解析 2xx 响应,否则将拒绝。有时我们不想要这个。我们要在解决时拒绝并在拒绝时解决。当您考虑使用 HEAD 请求检查某物是否存在时,这是有道理的。

    /book/fred 的 HEAD 请求返回 200 表明书 fred 存在。但是,如果我的函数是测试 book fred 是否是唯一的,那么它不是唯一的,所以我们想在 200 上拒绝。这就是 $q 的用武之地。现在我可以这样做:

    var defer = $q.defer();
    $http.head('/book/fred').then(function(response) {
        // 2xx response so reject because its not unique
        defer.reject(response);
    }).catch(function(failResponse) {
        defer.resolve(failResponse);
    });
    return defer.promise;
    

    $q 让我可以完全控制我何时拒绝以及何时解决。

    另外,$q 允许我以任何值拒绝或解决。因此,如果我只对某些响应感兴趣,我可以只用我感兴趣的部分来解决。

    最后,我可以使用 $q 将基于非承诺的代码变成承诺。

    var a = 5;
    var b = 10;
    var defer = $q.defer();
    var resolve(a+b);
    return defer.promise;
    

    波什,如果我需要一个承诺作为我的返回值,那么我有一个。

    这在模拟单元测试时也很棒。

    【讨论】:

      【解决方案2】:

      诸如$http$timeout$resource 等AngularJS 服务在内部使用$q 服务来生成它们的promise。对于这些服务,通常不需要注入 $q 服务。事实上,如果您看到 $q.defer 与这些服务一起使用,您应该询问 Is this a “Deferred Antipattern”?

      $q 服务的一些方法在某些情况下很有用。

      $q.all 方法用于等待多个承诺。

      var promise1 = $http.get(url1);
      var promise2 = $http.get(url2);
      
      $q.all([promise1, promise2]).then( responseArray ) {
          $scope.data1 = responseArray[0].data;
          $scope.data2 = responseArray[1].data;
      }).catch( function ( firstError ) {
          console.log(firstError.status)
      });
      

      .catch 方法可用于将拒绝的承诺转换为已履行的承诺。反之亦然,使用 .then 方法。无需为此使用$q.defer。如需更多信息,请参阅Angular execution order with $q

      $q.when 方法对于从未知来源生成承诺很有用。

       var promise = $q.when(ambiguousAPI(arg1));
      

      $q.when 方法在所有情况下都会创建一个$q 承诺,无论ambiguousAPI 返回一个值、$q 承诺还是来自另一个库的承诺。

      因为调用promise 的.then 方法会返回一个新的派生promise,所以很容易创建一个promise 链。可以创建任意长度的链,并且由于可以使用另一个 Promise 来解决一个 Promise(这将进一步推迟其解决方案),因此可以在链中的任何点暂停/推迟对 Promise 的解决。这使得实现强大的 API 成为可能。1

      总结一下: $q 服务用于创建承诺,因此在使用已经返回承诺的服务(如$http$timeout$resource 等)时您通常不需要使用$q 服务。

      【讨论】:

        【解决方案3】:

        在这种情况下,您当然不需要它,因为$http.get 本身会返回一个承诺。但是例如,如果您仅在某些条件下执行异步调用,则它很有用

        function acyncService () {
          if (dataLoaded) return $q.resolve(data);
          return $http.get('path/to/load/data');
        }
        

        这种情况下即使不执行异步调用,仍然可以使用

        acyncService().then(function(data){
          console.log(data);
        });
        

        这只是众多示例之一。当您使用其他库(例如 AWS SDK)进行异步请求时,使用 $q promises 也很有用。

        【讨论】:

        • 我正在努力理解您的回答,如果我错了,请纠正我。您是说 $q 用于创建承诺,因此当使用已经返回承诺的 acyncService(如 $http.get)时,您不需要使用 $q ?
        • 正确。事实上$http 服务使用$q 服务返回一个承诺。
        • 这种 $http 和 $q 组合的典型用例是一个 Angular 服务,它执行一次性加载(例如,来自 API 的静态数据的查找表),但随后调用将短路并返回已加载/缓存的数据。
        【解决方案4】:

        $http 进行异步调用。因此,理想情况下,如果您想在 url 中获取响应的值,您应该使用 '$scope' 变量来存储它。

           $http("your url").then(function(response){
              //This is the success callback
              $scope.movies = response.data;
              });
        

        【讨论】:

          猜你喜欢
          • 2014-02-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多