我希望得到用户从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
答案 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;
}