網站搜尋

javascript - RXJS 分頁的 while 迴圈


我嘗試從 swap api 查詢所有人的資料。URL swapi.co/api/people 返回一個包含 people 陣列的物件,而在 URL(swapi.co/api/people/?page=2) 我可以獲取下一頁的資料。我想做的是,每當有新的一頁資料可用時,subscribe 方法就會更新 angular 元件。

我對反應式編程模型還很陌生。我該如何實現 while 迴圈或一系列的 Observables?

這適用於第一頁:

getAllPeople(): Observable<Person[]> {
    let nextUrl = http://swapi.co/api;

    let source = Observable.create(observer => {

            this.http.get(nextUrl, { headers: this.headers })
            .map(response => {
                    let body = response.json();
                    nextUrl = body.next;
                    return nextUrl != null ? body.results as Person[] : null;
                }
            )
            .retry(5)//send same request based on the url of the previous request till the field next is null
            .catch(error => observer.error(error))
            .subscribe(persons => {
                    if (persons !== null) {
                        observer.next(persons)
                    }
                }
            );

        //observer.complete();
    })


    return source;
}

編輯:我添加了 retry() 方法。我希望這樣更容易理解我的意圖。第一次請求後,它會向相同的 URL 發送更多請求。不幸的是,它沒有使用我從先前請求中獲得的新 URL。

http://swapi.co/api/?page=1 -> http://swapi.co/api/?page=2 -> http://swapi.co/api/?page=3 -> 無

我不知道我需要多少次請求才能檢索所有數據。

答案#1

透過使用 expand 運算子,你可以為每個返回的值創建一個新的 Observable 序列。要停止 expand 創建任何新的序列,一旦我們得到下一個為 null 的 URL,我們可以返回一個空的 Observable 來停止擴展我們的序列。最後,我們可以使用 reduce 運算子將不同頁面的資料聚合成一個陣列,然後再發出回原始的訂閱者。這可以透過以下方式實現:

public getAllPeople(): Observable<Person[]> {
    return Observable.create(observer => {
          this.getPage("http://swapi.co/api/people/")
            .expand((data, i) => {
                return data.next ? this.getPage(data.next) : Observable.empty();
            })
            .reduce((acc, data) => {
                return acc.concat(data.results);
              }, [])
            .catch(error => observer.error(error))
            .subscribe((people) => {
                  observer.next(people);
                  observer.complete();
            });
    });
}

private getPage(url: string): Observable<{next: string, results: Person[]}> {
  return this.http.get(url, { headers: this.headers })
            .map(response => {
                    let body = response.json();
                    return {
                      next: body.next,
                      results: body.results as Person[]
                    };
                }
            );
}

示範