我想用promises调用一个分页API。一开始就不知道有多少页可用,但每次响应都会提供。详细说明我正在调用Jira search,分页信息部分如下:
{
"startAt": 0,
"maxResults": 15,
"total": 100000,
...
}
我解决了递归的分页处理问题,这是我在Typescript中的解决方案:
search(jql: string, fields: string[] = [], maxResults = 15) : Promise<JiraIssue[]> {
// container for the issues
let issues: Array<JiraIssue> = new Array<JiraIssue>();
// define recursive function to collect the issues per page and
// perform a recursive call to fetch the next page
let recursiveFn = (jql: string, fields: string[], startAt: number, maxResults: number) :
Promise<JiraIssue[]> => {
return this
// retrieves one page
.searchPage(jql, fields, startAt, maxResults)
.then((searchResult: JiraSearchResult) => {
// saves the result of the retrieved page
issues.push.apply(issues, searchResult.issues);
if (searchResult.startAt + searchResult.maxResults < searchResult.total) {
// retrieves the next page with a recursive call
return recursiveFn(jql, fields,
searchResult.startAt + searchResult.maxResults,
maxResults);
}
else {
// returns the collected issues
return issues;
}
})
};
// and execute it
return recursiveFn(jql, fields, 0, maxResults);
}
但是,我不喜欢递归方法,因为这适用于小结果集(我担心堆栈溢出)。你怎么用非递归方法解决这个问题呢?
答案 0 :(得分:2)
这不是实际的递归,并且没有堆栈溢出危险,因为函数是在then
处理程序内调用的。
答案 1 :(得分:1)
一种选择是将它包装在迭代器模式中。
类似的东西:
interface Searcher {
(jql: string, fields: string[], startAt: number, maxResults: number) => Promise<JiraSearchResult>;
}
class ResultsIterator {
private jql: string;
private fields: string[];
private searcher: Searcher;
private startAt: number;
private maxResults: number;
private currentPromise: Promise<JiraIssue[]>;
private total: number;
constructor(searcher: Searcher, jql: string, fields?: string[], maxResults?: number) {
this.jql = jql;
this.startAt = 0;
this.searcher = searcher;
this.fields = fields || [];
this.maxResults = maxResults || 15;
this.total = -1;
}
hasNext(): boolean {
return this.total < 0 || this.startAt < this.total;
}
next(): Promise<JiraIssue[]> {
if (!this.hasNext()) {
throw new Error("iterator depleted");
}
return this.searcher(this.jql, this.fields, this.startAt, this.maxResults)
.then((searchResult: JiraSearchResult) => {
this.total = searchResult.total;
this.startAt = searchResult.startAt + searchResult.maxResults;
return searchResult.issues;
});
}
}
这段代码并不完美,因为我不完全确定你在那里做什么(比如什么是this.searchPage
?),但你应该得到我的目标。
你会这样做:
if (resultIterator.hasNext()) {
resultIterator.next().then(...);
}
希望这有帮助。