2016-05-16 4 views
0

Ich möchte eine paginierte API mit Versprechungen aufrufen. Die Information, wie viele Seiten verfügbar sind, ist zu Beginn nicht bekannt, wird aber bei jeder Antwort geliefert. Im Einzelnen ich einen Jira nenne search, der Paging-Informationsteil wie folgt aussieht:Aufruf einer paginierten API mit Versprechungen

{ 
    "startAt": 0, 
    "maxResults": 15, 
    "total": 100000, 
    ... 
} 

ich den Umgang mit der Paginierung mit Rekursion gelöst, das ist meine Lösung in Typoskript:

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

Aber ich mag den rekursiven Ansatz nicht, da dies nur mit kleinen Resultsets funktioniert (ich habe Angst vor einem Stacküberlauf). Wie würden Sie dieses Problem mit einem nicht rekursiven Ansatz lösen?

+1

Dies ist keine tatsächliche Rekursion, und es besteht keine Stapelüberlaufgefahr, weil die Funktion innerhalb eines then aufgerufen wird. –

Antwort

2

Dies ist keine tatsächliche Rekursion, und es besteht keine Stapelüberlaufgefahr, da die Funktion innerhalb eines then-Handlers aufgerufen wird.

1

Eine Option besteht darin, dies in ein Iteratormuster zu verpacken.

Etwas wie:

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

Dieser Code ist nicht perfekt, da ich nicht ganz sicher bin, was du da tust (zum Beispiel was this.searchPage ist?), Aber man sollte wohl auf die Idee kommen I ziele darauf ab.

Sie werden gerade tun:

if (resultIterator.hasNext()) { 
    resultIterator.next().then(...); 
} 

Hoffnung, das hilft.