2017-05-21 44 views
2

我嘗試查詢swap api中的所有人員數據。網址swapi.co/api/people會返回一個包含people數組的對象和URL(swapi.co/api/people/?page=2),我將從中獲取下一個數據。我想要做的是,每次有新頁面可用時,訂閱方法都會更新角度分量。RXJS用於分頁的循環

我是新來的反應式編程模型。我如何實現一個while循環或一系列Observable?

這適用於第一頁:

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

編輯: 我添加重試()方法。我希望理解我打算做什麼更容易。在第一個請求之後,它會向同一個URL發送更多請求。不幸的是,它沒有使用我從前一個請求中獲得的新URL。

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

我不知道我需要多少個請求檢索的所有數據。

+0

你可能需要使用WebSockets,以獲取有關新頁面的通知。 –

+0

我不熟悉websockets,但我認爲這不是我所需要的。 http獲取請求對服務器的響應告訴我在哪裏獲取下一個數據。 – qwerty

+0

當然,如果您只需要獲取所有頁面 - 您不需要它,但是您的問題是能夠在每次有新頁面可用時更新。 –

回答

3

通過使用expand操作,您可以創建返回的每個值的新的可觀察序列。要停止expand創建任何新序列,一旦我們得到下一個空的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[] 
        }; 
       } 
      ); 
} 

Demo

+0

如果使用toArray而不是reduce,結果是否相同?我很困惑他們有什麼不同。 – samcp20

+0

通常是的,但由於結果已經是一個數組,如果你使用'toArray()',你最終會得到一個數組數組。此外,reduce方法也將結果解包,以便它不是一個對象,而是一組人對象。 –

+0

啊我明白了,有道理。 – samcp20

1

使用擴大運營商,如:

function getData(id) { 
    let next = id<5 ? id+1 : null; 
    let obj = {id:id, next:next} 
    return next ? Rx.Observable.of(obj) : Rx.Observable.empty(); 
} 

getData(0) 
    .expand(el=> getData(el.next)) 
    .subscribe(x=>console.log(x)); 
+1

您是否真的嘗試過?我不確定它會起作用,因爲'getData'函數只會被調用一次。而'getData'的結果將作爲'el'返回到'expand'操作。 – user3743222

+1

它會多次調用,直到下一個是eq 5.將代碼過濾到jsbin中並檢查。這被稱爲遞歸。 –

+0

感謝Julia,擴展方法(遞歸調用提供的函數)正是我所期待的。我的問題的標題沒有很好的選擇。 – qwerty