我如何使用来自 angular 工厂的循环发送程序请求(一个接一个)?
how do I send procedural requests (one after the other) with loop from angular factory?
我希望获得用户从 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 人,则总数将达到 return。我正在通过这样的控制器使用这个工厂:
// grab the artists they follow
artists.getUserFollowing().then(function(artistsUserFollows){
$rootScope.artistTotal = artistsUserFollows.length;
$rootScope.artists = artistsUserFollows;
});
我如何编写一个循环,以便 getUserFollowing()
将 return 一个包含所有艺术家的数组,无论他们是否关注任何艺术家或 1000 位艺术家?如果他们关注 1000 位艺术家,那么我们需要发送 20 个请求 (1000/50),或者如果他们没有关注任何艺术家,则只需发送一个请求。
如何发送动态数量的请求以获取用户关注的所有艺术家,一次 50 个?此外,请求的下一个 url(无身份验证 header)在 res.data.artists.next
中定义
更新的解决方案
我认为你需要一个递归的解决方案来解决这个问题。我没有测试过这个,但我认为它应该可以工作。如果您有任何问题,请告诉我进展情况。
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 将问题从 "concurrent" 请求更改为 "procedural" 请求。
快速浏览了 Spotify 的 API 详细信息后,似乎 并发 无法解决您的问题。 Spotify 使用基于游标的分页,其中每个 HTTP 响应都包含用于检索下一组项目的游标。我相信这是他们针对可能的拒绝服务攻击选择的一种防御机制。
https://developer.spotify.com/web-api/object-model/#cursor-based-paging-object
我认为唯一的选择将与您已经在使用的非常相似,即将多个承诺链接在一起,直到您检索到所有艺术家。
编辑:将并行替换为并发以避免混淆。 :)
这是处理此问题的一种解决方案。使用单一承诺让您的应用程序知道所有艺术家的检索何时完成。该函数的每次迭代都会向下一个 url 发出请求(从最初的 spotify api 调用开始),附加它接收到的项目,然后在需要更多项目时调用自身,或者如果没有,则使用内置数组解决承诺。
这只是一个简单示例,您可能需要根据自己的用途进行修改。类似于以下内容:
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;
}
我希望获得用户从 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 人,则总数将达到 return。我正在通过这样的控制器使用这个工厂:
// grab the artists they follow
artists.getUserFollowing().then(function(artistsUserFollows){
$rootScope.artistTotal = artistsUserFollows.length;
$rootScope.artists = artistsUserFollows;
});
我如何编写一个循环,以便 getUserFollowing()
将 return 一个包含所有艺术家的数组,无论他们是否关注任何艺术家或 1000 位艺术家?如果他们关注 1000 位艺术家,那么我们需要发送 20 个请求 (1000/50),或者如果他们没有关注任何艺术家,则只需发送一个请求。
如何发送动态数量的请求以获取用户关注的所有艺术家,一次 50 个?此外,请求的下一个 url(无身份验证 header)在 res.data.artists.next
更新的解决方案
我认为你需要一个递归的解决方案来解决这个问题。我没有测试过这个,但我认为它应该可以工作。如果您有任何问题,请告诉我进展情况。
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 将问题从 "concurrent" 请求更改为 "procedural" 请求。
快速浏览了 Spotify 的 API 详细信息后,似乎 并发 无法解决您的问题。 Spotify 使用基于游标的分页,其中每个 HTTP 响应都包含用于检索下一组项目的游标。我相信这是他们针对可能的拒绝服务攻击选择的一种防御机制。
https://developer.spotify.com/web-api/object-model/#cursor-based-paging-object
我认为唯一的选择将与您已经在使用的非常相似,即将多个承诺链接在一起,直到您检索到所有艺术家。
编辑:将并行替换为并发以避免混淆。 :)
这是处理此问题的一种解决方案。使用单一承诺让您的应用程序知道所有艺术家的检索何时完成。该函数的每次迭代都会向下一个 url 发出请求(从最初的 spotify api 调用开始),附加它接收到的项目,然后在需要更多项目时调用自身,或者如果没有,则使用内置数组解决承诺。
这只是一个简单示例,您可能需要根据自己的用途进行修改。类似于以下内容:
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;
}