簡體   English   中英

如何組合 mergeMap observables 調用並為整個 observable 只返回一個值

[英]How to combine mergeMap observables calls and return just one value for the whole observable

我在使用 rxjs 6.5 的打字稿/角度中有這種情況:

   main(){

        const properties = ['session', 'user'];
        const source: Observable<any> = from(properties);

        source
            .pipe(
                mergeMap(key => this.getKey().map((value) => ({key: key, value: value}))),
                tap((result) => {
                    // sending the result elsewhere;
                }),
            ).subscribe(
            (result) => {
                console.log('Final result ->', result);
            }
        );

        console.log('\n');

    }

    getKey(): Observable<any> {
        // Mock function that returns an observable that emits 1 value
        const observable = from(['test']);

        return observable;
    }

輸出是:

Final result -> {key: "session", value: "test"}
Final result -> {key: "user", value: "test"}

第一個問題:如何以最優雅的方式在訂閱源時僅返回 1 個值以及內部可觀察量的組合結果?

我想要的輸出,以這種方式訂閱(因為我希望這個組合操作在管道中),將是:

(...).subscribe(
(result) => {console.log('Final Result:', result}
)

OUTPUT:

Final result -> [{key: "session", value: "test"}, {key: "user", value: "test"}]

第二個問題如果我不關心內部 observables 的結果,我如何只返回 1 個值或者我怎么知道所有內部 observables 何時完成?

提前致謝。

要獲得 mergeMap 的所有響應的組合結果,您也可以這樣嘗試:

return this.request1().pipe(
  mergeMap(res1=> this.request2(res1.id).pipe(
    map(res2=> {
      return {
        res1: res1,
        res2: res2
      }
    })
  ))
)

Q1:您需要一個toArray — 它將所有流值組合到一個數組中:

toArray 示例

Q2:省略流中的所有值並在完成時發出一個值

concat(
  source$.pipe(ignoreElements()),
  of(true)
)

在源完成時發出一個值

請參閱 playground 中的在源代碼完成時發出值示例

這是一個帶注釋的示例,可幫助您澄清有關您詢問的訂閱過程的問題。

Q1:

正如另一個答案中所指出的, reduce運算符是您希望包含在source管道中的內容。 reduce的一個關鍵細節是它只在相應的源可觀察對象完成時發出。 相反,如果您希望在這些內部可觀察量完成時發射,則scan是合適的。 與后者的另一個區別是它不需要源代碼完成。

Q2:

帶着這個問題,參考我下面的例子,將處理管道的每個參數都視為單個請求的生命周期。 在這里,完成是隱含的。 它發生在內部可觀察量的最后一個值被處理之后。

但是,如果內部可觀察對象沒有界限,那么就不可能知道所有內部可觀察對象何時完成。 在這種情況下,您會發現reduce()不起作用。

 const { from, of, Subject } = rxjs; const { mergeMap, map, tap, reduce, scan } = rxjs.operators; // Use a subject to simulate processing. // Think of each argument as a request to the processing pipeline below. const properties = new Subject(); // Establish processing pipeline const source = properties.pipe( // `mergeMap` here flattens the output value to the combined inner output values mergeMap(props => // Each item inside the argument should be piped as separate values from(props).pipe( // `mergeMap` here flattens the output value to `{ key, value }` mergeMap(key => of('test').pipe( map(value => ({ key, value })), ), ), // Unlike `scan`, `reduce` only emits upon "completion". // Here, "completion" is implicit - it is after the last // element of `from(props)` has been processed. reduce((a, i) => [...a, i], []), ) ), ); // Subscribe to the pipeline to observe processing. source.subscribe(console.log); // Trigger a processing request with an argument properties.next(['session', 'user']); // Trigger another processing request properties.next(['session', 'user']);
 <script src="https://unpkg.com/rxjs@6.5.1/bundles/rxjs.umd.min.js"></script>

使用減少

.pipe(
  reduce((results, result) => {
    results.push(result);
    return results;
  }, [])
)

生成的可觀察對象只會在所有其他對象都發出后才會發出,並且發出的值將是所有結果的數組。

第一個問題,你可以使用scan來處理和累積輸出

 mergeMap(key => from(this.getKey())),
 scan((acc,curr) =>acc.concat([{key: curr.key, value: curr.value}]),[])),

2n 問題

使用first()運算符僅從內部可觀察對象中獲取一個輸出,將finalize()附加到內部可觀察對象,這將在內部可觀察對象完成時觸發。 或使用last()獲取最后的累積結果

 mergeMap(key => from(this.getKey())),
 scan((acc,curr) =>acc.concat([{key: curr.key, value: curr.value}]),[])),
 first()

暫無
暫無

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

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