【问题标题】:Calling a paginated API with promises使用 Promise 调用分页 API
【发布时间】:2016-05-16 11:19:21
【问题描述】:

我想用 Promise 调用分页 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);
}

但是,我不喜欢递归方法,因为这只适用于小的结果集(我担心堆栈溢出)。您将如何使用非递归方法解决此问题?

【问题讨论】:

  • 这不是真正的递归,也没有堆栈溢出的危险,因为函数是在 then 内部调用的。

标签: javascript recursion typescript pagination promise


【解决方案1】:

这不是真正的递归,也没有堆栈溢出的危险,因为函数是在 then 处理程序中调用的。

【讨论】:

    【解决方案2】:

    一种选择是将其包装在迭代器模式中。

    类似:

    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(...);
    }
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-15
      • 2017-04-04
      • 2018-02-01
      • 2017-02-25
      • 2021-07-06
      • 1970-01-01
      • 1970-01-01
      • 2022-10-04
      相关资源
      最近更新 更多