簡體   English   中英

如何在 RxJS 中“等待”兩個 observables

[英]How to 'wait' for two observables in RxJS

在我的應用程序中,我有類似的東西:

this._personService.getName(id)
      .concat(this._documentService.getDocument())
      .subscribe((response) => {
                  console.log(response)
                  this.showForm()
       });

 //Output: 
 // [getnameResult]
 // [getDocumentResult]

 // I want:
 // [getnameResult][getDocumentResult]

然后我得到兩個單獨的結果,首先是_personService ,然后是_documentService 在調用this.showForm()之前如何等待兩個結果來完成然后操作每個結果。

最后更新:2022 年 3 月。

RxJS v7: combineLatestWith

從 reactiveX文檔

每當任何輸入 Observable 發出一個值時,它都會使用來自所有輸入的最新值計算一個公式,然后發出該公式的輸出。

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();
    
name$.pipe(
        combineLatestWith($document)
      )
      .subscribe(([name, document]) => {
           this.name = name;
           this.document = pair.document;
           this.showForm();
       })

(已棄用)RxJS v6 combineLatest()

從 reactiveX 文檔

每當任何輸入 Observable 發出一個值時,它都會使用來自所有輸入的最新值計算一個公式,然后發出該公式的輸出。

(更新:2021 年 2 月)

// Deprecated (RxJS v6)
// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();
    
name$.combineLatest(document$, (name, document) => {name, document})
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

(替代語法) : combineLatest(observables)

// Deprecated (RxJS v6)
// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();
    
combineLatest(name$, document$, (name, document) => ({name, document}))
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

zip vs combineLatest

(更新:2018 年 10 月)我之前建議使用zip方法。 但是,對於某些用例, combineLatestzip有一些優勢。 因此,了解這些差異很重要。

CombineLatest從 observables 發出最新的發射值。 zip方法按順序發出發出的項目。

例如,如果 observable #1 發出了它的第 3 個item,而 observable #2 發出了它的第 5 個item。 使用zip方法的結果將是兩個observables第三個發射值。

在這種情況下,使用combineLatest的結果將是5th3rd 感覺更自然。


Observable.zip(可觀察)

(原始答案:2017 年 7 月) Observable.zip 方法在reactiveX 文檔中進行了解釋:

組合多個 Observable 以創建一個 Observable,其值是按順序從其每個輸入 Observable 的值中計算出來的。

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();
    
Observable
    .zip(name$, document$, (name: string, document: string) => ({name, document}))
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

附注(適用於兩種方法)

最后一個參數,我們提供了一個函數, (name: string, document: string) => ({name, document})是可選的。 你可以跳過它,或者做更復雜的操作:

如果最新參數是函數,則此函數用於根據輸入值計算創建值。 否則,返回輸入值數組。

所以如果你跳過最后一部分,你會得到一個數組:

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();
    
Observable
    .zip(name$, document$)
    .subscribe(pair => {
           this.name = pair['0'];
           this.document = pair['1'];
           this.showForm();
       })

使用 observables 的forkJoin()方法。 檢查此鏈接以供參考

來自 RXJS文檔

當您有一組可觀察對象並且只關心每個對象的最終發出值時,最好使用此運算符。 一個常見的用例是,如果您希望在頁面加載(或其他事件)時發出多個請求,並且只想在收到所有人的響應時采取行動。 通過這種方式,它類似於您使用Promise.all 的方式

forkJoin([character, characterHomeworld]).subscribe(results => {
  // results[0] is our character
  // results[1] is our character homeworld
  results[0].homeworld = results[1];
  this.loadedCharacter = results[0];
});

代碼取自: https ://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs

傻瓜的 RxJS 運算符:forkJoin、zip、combineLatest、withLatestFrom對我幫助很大。 顧名思義,它描述了以下組合運算符:

其中任何一個都可能是您正在尋找的東西,具體取決於具體情況。 查看文章了解更多信息。

改進了使用直接參數分解並自動添加類型的Hamid Asghari 答案(當您使用打字稿時)

 const name$ = this._personService.getName(id); const document$ = this._documentService.getDocument(); combineLatest([name$, document$]).subscribe(([name, document]) => { this.name = name; this.document = document; this.showForm(); });

獎勵:您還可以使用上述方法處理錯誤,如下所示

 import { combineLatest, of } from 'rxjs'; //... const name$ = this._personService.getName(id); const document$ = this._documentService.getDocument(); combineLatest([ name$.pipe( catchError( () => of(null as string ) ) ), document$.pipe( catchError( () => of(null as Document) ) ), // 'Document' is arbitrary type ]).subscribe(([name, document]) => { this.name = name; // or null if error this.document = document; // or null if error this.showForm(); });

2021 年 6 月

使用 rxjs 6.6.7

像這樣使用combineLatest否則被棄用

combineLatest([a$ , b$]).pipe(
      map(([a, b]) => ({a, b})) //change to [a , b] if you want an array
    )

另見@nyxz 帖子

zip - 愛情鳥,始終作為一個團隊工作,僅在所有可觀察對象返回新值時觸發

combineLatest - go dutch,一旦所有可觀察對象返回新值就開始觸發,然后等待無人,每次當任一可觀察對象返回新值時觸發。

withLatestFrom - 主從,主先等待從,之后,只有當主返回新值時才會觸發動作。

forkJoin - 最終目的地,當所有可觀察對象完成時觸發一次。

來自: https ://scotch.io/tutorials/rxjs-operators-for-dummies-forkjoin-zip-combinelatest-withlatestfrom/amp

看看 'combineLatest' 方法,這里可能合適。 http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-combineLatest

const { Observable } = Rx

const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .combineLatest(name$, document$, (name, document) => ({ name, document }))
    .first() // or not, implementation detail
    .subscribe(({ name, document }) => {
        // here we have both name and document
        this.showForm()
    })

對我來說,這個 樣本是最好的解決方案。

const source = Observable.interval(500);
const example = source.sample(Observable.interval(2000));
const subscribe = example.subscribe(val => console.log('sample', val));

所以..只有當第二個(示例)發射時 - 你會看到第一個(源)的最后一個發射值。

在我的任務中,我等待表單驗證和其他 DOM 事件。

您可以使用“zip”或“buffer”,如下所示。

function getName() {
    return Observable.of('some name').delay(100);
}

function getDocument() {
    return Observable.of('some document').delay(200);
}

// CASE1 : concurrent requests
Observable.zip(getName(), getDocument(), (name, document) => {
    return `${name}-${document}`;
})
    .subscribe(value => console.log(`concurrent: ${value}`));

// CASE2 : sequential requests
getName().concat(getDocument())
    .bufferCount(2)
    .map(values => `${values[0]}-${values[1]}`)
    .subscribe(value => console.log(`sequential: ${value}`));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM