如何使用角度工厂的循环发送程序请求(一个接一个)?

时间:2015-11-16 19:40:14

标签: javascript angularjs asynchronous promise spotify

我希望得到用户从Spotify中获取的所有艺术家。问题是,我一次只能请求50位艺术家,并且只知道第一次请求后的艺术家总数。我的工厂看起来像这样:

app.factory('artists', [
    "$rootScope", 
    "$http",
    "$cookies",
    "$q",
    function($rootScope, $http, $cookies, $q){

    return {
        getUserFollowing: function(){
            var allArtists = [];
            var _params = {
                type: 'artist',
                limit: 50, // maximum
            };
            var _authConfig = {
                'Authorization': 'Bearer ' + $cookies.get('spotify-token'),
                'Content-Type': 'application/json'
            };

            var req = {
                method: 'GET',
                url: 'https://api.spotify.com/v1/me/following',
                headers: _authConfig,
                params: _params
            };
            return $http(req).then(function(res){

                var artistTotal = res.data.artists.total;
                allArtists = allArtists.concat(res.data.artists.items);

                if(allArtists.length < artistTotal){
                    // send the request again to load 50 more artists
                    return $http({
                        method: 'GET',
                        url: res.data.artists.next,
                        headers: _authConfig,
                    }).then(function(nextRes){
                        allArtists = allArtists.concat(nextRes.data.artists.items);
                        return allArtists;
                    });
                } else {
                    // need to return a promise
                    var dfd = $q.defer();
                    dfd.resolve(allArtists);
                    return dfd.promise;
                }
            });
        }
    };
}]);

在上述请求中,如果用户关注超过50位艺术家,我会另外发送请求(另外50位)。如果他们关注不到50位艺术家,那么它将返回总数。我从这样的控制器使用这个工厂:

// grab the artists they follow
artists.getUserFollowing().then(function(artistsUserFollows){
    $rootScope.artistTotal = artistsUserFollows.length;
    $rootScope.artists = artistsUserFollows;
});

我如何编写一个循环,以便getUserFollowing()将返回所有艺术家的数组,无论他们是否跟随没有艺术家或1000名艺术家?如果他们关注1000名艺术家,那么我们需要发送20个请求(1000/50),或者如果他们不跟踪艺术家只有一个请求。

如何发送动态数量的请求以吸引用户跟随的所有艺术家,一次50个?此外,请求的下一个网址(没有auth标头)在res.data.artists.next

中定义

2 个答案:

答案 0 :(得分:1)

更新的解决方案

我认为你需要一个针对这个问题的递归解决方案。我没有测试过这个,但我认为它应该可行。让我知道它是怎么回事,如果你有任何问题。

var recursiveFunc = function(promises, allArtists, next) {

var req = {
    method: 'GET',
    url: next || 'https://api.spotify.com/v1/me/following',
    headers: _authConfig,
    params: _params
};

return $http(req)
    .then(function(res) {

        var artistTotal = res.data.artists.total;

        for(var i=0; i<res.data.artists.items; i++) {
            allArtists.push(res.data.artists.items[i]);
        }

        if (allArtists.length < artistTotal) {
            promises.push(recursiveFunc(res.data.artists.next));
        }
    });
}

var promises = [];
var allArtists = [];

recursiveFunc(promises, allArtists);

$q.all(promises).then(function() {
    console.log('All Artists', allArtists);
});

旧解决方案

更新:由于OP将问题从“并发”请求更改为“程序性”请求,因此此答案不再相关。

在快速浏览Spotify的API详细信息后,似乎无法解决您的问题的并发解决方案。 Spotify使用基于游标的分页,其中每个HTTP响应包含用于检索下一组项目的游标。我认为这是他们选择的一种防御机制,可以抵御可能的拒绝服务攻击。

https://developer.spotify.com/web-api/object-model/#cursor-based-paging-object

我认为唯一的选择将与你已经使用的非常相似,即将多个承诺链接在一起直到你找回所有的艺术家。

编辑:与并发替换并行以避免混淆。 :)

答案 1 :(得分:0)

这是解决此问题的一种解决方案。使用单一承诺,让您的应用程序在完成所有艺术家的检索时知道。函数的每次迭代都会向下一个url发出请求(从初始的spotify api调用开始),附加它接收的项目,然后在需要更多项目的情况下调用自身,或者使用构建的数组解析promise不

这只是一个简单的示例,您可能需要根据自己的需要进行修改。如下所示:

function getAllArtists() {
  var deferred = $q.defer();
  var allArtists = [];

  var getArtists = function (url) {
    var req = { 
      // request details
      method: 'GET',
      url: url
      // ... other req options
    };

    $http(req).then(function (res) {
      var artistTotal = res.data.artists.total;
      allArtists = allArtists.concat(res.data.artists.items);

      if(allArtists.length < artistTotal) {
        // need more artists
        getArtists(res.data.artists.next);
      } else {
        // we have all artists
        deferred.resolve(allArtists);
      }
    }
  }

  getArtists('https://api.spotify.com/v1/me/following');

  return deferred.promise;
}