[英]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
— 它將所有流值組合到一個數組中:
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.