如何使用RxJS的mergeMap()处理3个Observable?
Got it, let's figure out how to handle multiple Observables with mergeMap() (and even a better alternative for your specific input-splicing use case!)
First, let's fill out the RxJS setup for your three input fields since your code snippet cut off. We'll start by creating Observables for each input's input event, mapping to their current value.
Nested mergeMap() for 3 Observables
mergeMap() works by taking a value from the source Observable, returning a new Observable, and merging its emissions into the main stream. For three Observables, you can nest mergeMap() calls to access all three values:
import { fromEvent } from 'rxjs'; import { mergeMap, map } from 'rxjs/operators'; const input1 = document.querySelector('#input1'); const input2 = document.querySelector('#input2'); const input3 = document.querySelector('#input3'); const span = document.querySelector('span'); // Create Observables for each input's value changes const input1$ = fromEvent(input1, 'input').pipe(map(e => e.target.value)); const input2$ = fromEvent(input2, 'input').pipe(map(e => e.target.value)); const input3$ = fromEvent(input3, 'input').pipe(map(e => e.target.value)); // Nest mergeMap to combine all three values input1$.pipe( mergeMap(val1 => input2$.pipe( mergeMap(val2 => input3$.pipe( // Combine the three values into your desired string map(val3 => `${val1} ${val2} ${val3}`) )) )) ).subscribe(combinedText => { span.textContent = combinedText; });
This works because each mergeMap() passes the previous value (val1, then val2) into the next Observable stream, letting you finally combine all three in the innermost map(). That said, nested mergeMap() can get messy with more than 2-3 Observables—especially when your inputs are independent (like form fields where each change should update the combined text immediately).
A Cleaner Alternative for Independent Inputs: combineLatest
For your use case (dynamically splicing three input values), combineLatest is a much better fit. It listens to all provided Observables, and whenever any of them emits a new value, it emits an array of the latest values from all Observables. This is perfect for form inputs where you want to sync all changes in real-time:
import { fromEvent, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; // Reuse the same input Observables and element references as above combineLatest([input1$, input2$, input3$]).pipe( // Destructure the array of latest values and combine them map(([val1, val2, val3]) => `${val1} ${val2} ${val3}`) ).subscribe(combinedText => { span.textContent = combinedText; });
This code is shorter, more readable, and behaves exactly how you'd want for form input syncing.
When to Use mergeMap() vs combineLatest
- Use nested
mergeMap()when your Observables are dependent: e.g., you need to fetch data from an API using a value from the first Observable, then fetch more data using the result of that API call. - Use
combineLatestwhen your Observables are independent and you need to react to any of their latest values (like form inputs, dashboard widgets, etc.).
内容的提问来源于stack exchange,提问作者Shaun Chua

