利用YouTube数据API,我们可以进行查询以获取属于以下用户的用户的前50个视频(通过单个查询可获得的最大结果数):https://www.googleapis.com/youtube/v3/search?key={access_key}&channelId={users_id}&part=id&order=date&maxResults=50&type=video
如果视频超过50个,则生成的JSON将具有一个nextPageToken
字段,以获取接下来的50个视频,我们可以将&pageToken={nextPageToken}
附加到上述请求中,从而产生下一个50页视频。这可以重复,直到nextPageToken
字段不再存在。
这是我使用fetch API编写的一个简单的JavaScript函数,用于获取视频的单个页面,该页面由nextPageToken
参数指定(或不指定)。
function getUploadedVideosPage(nextPageToken) {
return new Promise((resolve, reject) => {
let apiUrl = 'https://www.googleapis.com/youtube/v3/search?key={access_key}&channelId={users_id}&part=id&order=date&maxResults=50&type=video';
if(nextPageToken)
apiUrl += '&pageToken=' + nextPageToken;
fetch(apiUrl)
.then((response) => {
response.json()
.then((data) => {
resolve(data);
});
});
});
}
现在,我们需要一个包装函数,只要我们有一个getUploadedVideosPage
,它就会迭代地调用nextPageToken
。这是我的“工作”方式,尽管很危险(稍后会详细介绍)。
function getAllUploadedVideos() {
return new Promise((resolve, reject) => {
let dataJoined = [];
let chain = getUploadedVideosPage();
for(let i = 0; i < 20000; ++i) {
chain = chain
.then((data) => {
dataJoined.push(data);
if(data.nextPageToken !== undefined)
return getUploadedVideosPage(data.nextPageToken);
else
resolve(dataJoined);
});
}
});
}
“危险”方面是for循环的条件,理论上应该是无限for(;;)
,因为我们没有预定义的方式来确切知道要进行多少次迭代,而终止循环的唯一方法应该是与resolve
语句一起使用。但是,当我以这种方式实现它时,它实际上是无限的,永远不会终止。
因此,为什么我要对20,000次迭代进行硬编码,并且看来可行,但是我不相信该解决方案的可靠性。我希望这里的人可以阐明如何实现没有预定义终止条件的迭代Promise链。
答案 0 :(得分:2)
您可以使用一个调用自身的函数(如果适用)来完成全部操作。
由于fetch()
已经返回了诺言,因此您还使用explicit promise construction anti-pattern将new Promise
包装在fetch()
中
function getVideos(nextPageToken, results = []) {
let apiUrl = 'https://www.googleapis.com/youtube/v3/search?key={access_key}&channelId={users_id}&part=id&order=date&maxResults=50&type=video';
if (nextPageToken) {
apiUrl += '&pageToken=' + nextPageToken;
}
// return fetch() promise
return fetch(apiUrl)
.then(response => response.json())
.then(data => {
// merge new data into final results array
results = results.concat(data);
if (data.nextPageToken !== undefined) {
// return another request promise
return getVideos(data.nextPageToken, results);
} else {
// all done so return the final results
return results
}
});
}
// usage
getVideos().then(results=>{/*do something with all results*/})
.catch(err=>console.log('One of the requests failed'));
答案 1 :(得分:1)
完全摆脱for循环。像这样:
function getAllUploadedVideos() {
return new Promise((resolve, reject) => {
let dataJoined = [];
function getNextPage(nextPageToken) {
return new Promise((resolve, reject) => {
getUploadedVideosPage(nextPageToken)
.then((data) => {
dataJoined.push(data);
if(data.nextPageToken !== undefined) {
resolve(data.nextPageToken);
}
else {
reject();
}
})
.catch((err) => {
// Just in case getUploadedVideosPage errors
reject(err);
});
});
}
getNextPage()
.then((nextPageToken) => {
getNextPage(nextPageToken);
})
.catch(() => {
// This will hit when there is no more pages to grab
resolve(dataJoined);
});
});
}