Angular 在服务内部移动成功递归回调

Angular move success recursive callback inside service

我有一项 returns $http 承诺的服务。这工作正常,但我需要进行递归调用以防列表 returns 超过 100 个项目。同样,这工作正常,但我要为每个控制器重复一遍。我无法将递归卸载到服务并仍然得到最终结果。也许 $q 能帮上忙?

// service
function List ($http) {
  var headers = {'Accept': 'application/json;odata=verbose'}
    , listService = {
        getByName: function (listName) {
          return $http({
            method: 'GET'
          , url: '/_api/web/lists/getByTitle(\'' + listName + '\')/items'
          , headers: headers
          });
        }

      , getByUrl: function (url) {
          return $http({
            method: 'GET'
          , url: url
          , headers: headers
          })
        }
  };

  return listService;
}

// controller
function Calendar ($scope, List) {
  $scope.events = [];

  List.getByName('Calendar').success(function (response) {
    $scope.events = response.d.results;
    if (response.d.__next) {
      List.getByUrl(response.d.__next).success(recursiveSuccess);
    }
  });

  function recursiveSuccess (response) {
    $scope.events = $scope.events.concat(response.d.results);
    if (response.d.__next) {
      List.getByUrl(response.d.__next).success(recursiveSuccess);
    }
  }
}

由于每次调用都会为您提供下一个端点的 URL,因此 必须 在连续的 HTTP 调用中完成。就承诺而言,它在概念上会像这样完成:

return firstCall.then(function(data){
  return secondCall(data);
})
// another .then
// another .then
.then(function(data){
  return lastCall(data);
});

这里的每个 NCall 都是一个函数,它获取上一个调用的数据和 returns 对下一个聚合数据的承诺,以及 lastCall returns 最终聚合数据.

如果将其转换为递归函数,它将如下所示:

function getItemsFrom(url, items){

  return $http.get(url).then(function(response){

    items = items.concat(response.data.items);

    if (response.data.next){
      return getItemsFrom(response.data.next, items);
    } else {
      return items;
    }
  });
}

数据为:

{
  "next": "url/to/data2.json",
  "items": [1, 2, 3]
}

唯一剩下的就是最初的调用:

.factory("fooSvc", function($http){
  function getItemsFrom(url, items){
    // as above
  }

  return {
    getItems: function(){
      return getItemsFrom("url/to/data1.json", []);
    }
  };
});

Demo

是的,我遇到过类似的问题,我不得不在服务的一个方法中进行多次调用,使用 $q 解决了这个问题。一旦你学会了如何使用它,它会非常强大。

在您的服务方式中:

function promiseYoullCallMeWhenYoureComplete () {
    var deferred = $q.defer();
    var events = [];

    startMyQuery();

    return deferred.promise;

    ////////////

    function startMyQuery () {
       List.getByName('Calendar').then(success, error);
    }

    function success (response) {
        // perform success actions
        events = angular.extend(events, response.data.d.results);

        // run next query or exit if complete
        if (response.data.next) {
           return startMyQuery();
        }

        // no more queries, so exit and return my combined events array
        return deferred.resolve(events);
    }

    function error (response) {
        return deferred.reject(response);
    }
}

然后在你的控制器中,像这样:

List.promiseYoullCallMeWhenYoureComplete().then(success, error);

///////////

function success (events) {
    $scope.events = events;
}

function error (response) {
    console.error("Error:", response);
}

通过这种方式,您的服务可以进行 $http 查询,直到奶牛回家,但您的控制器只会收到一个单一的响应来处理(成功,其中包含您通过 resolve(...) 方法,或错误。因此您的控制器非常干净,因为您可以将所有逻辑移至服务中。