zip
Combines multiple Observables to create an Observable whose values are calculated from the values, in order, of each of its input Observables.
Import
import { zip } from 'rxjs';
Type Signature
// Array form
function zip<A extends readonly unknown[]>(
sources: [...ObservableInputTuple<A>]
): Observable<A>;
// Variadic form
function zip<A extends readonly unknown[]>(
...sources: [...ObservableInputTuple<A>]
): Observable<A>;
// With result selector
function zip<A extends readonly unknown[], R>(
...sourcesAndResultSelector: [...ObservableInputTuple<A>, (...values: A) => R]
): Observable<R>;
Parameters
sources
Array<ObservableInput>
required
Multiple Observables to combine by index.
Optional function to transform the combined values.
Returns
An Observable that emits arrays of values taken from the same index of each input Observable.
Description
zip combines Observables by pairing up their emissions by index. It waits for all Observables to emit at each index before emitting the combined array.
Key characteristics:
- Emits when ALL Observables have emitted at the current index
- Pairs values by their emission order (1st with 1st, 2nd with 2nd, etc.)
- Completes when ANY Observable completes
- Buffers values if Observables emit at different rates
Examples
Basic Zip
import { zip, of } from 'rxjs';
const age$ = of(27, 25, 29);
const name$ = of('Foo', 'Bar', 'Beer');
const isDev$ = of(true, true, false);
zip(age$, name$, isDev$).subscribe(([age, name, isDev]) => {
console.log({ age, name, isDev });
});
// Output:
// { age: 27, name: 'Foo', isDev: true }
// { age: 25, name: 'Bar', isDev: true }
// { age: 29, name: 'Beer', isDev: false }
With Result Selector
import { zip, of } from 'rxjs';
import { map } from 'rxjs/operators';
const age$ = of(27, 25, 29);
const name$ = of('Foo', 'Bar', 'Beer');
zip(age$, name$).pipe(
map(([age, name]) => ({ age, name }))
).subscribe(person => console.log(person));
Different Emission Rates
import { zip, interval, of } from 'rxjs';
import { take } from 'rxjs/operators';
const slow$ = interval(1000).pipe(take(3)); // 0, 1, 2 (one per second)
const fast$ = of('a', 'b', 'c'); // emits immediately
zip(slow$, fast$).subscribe(([slow, fast]) => {
console.log(slow, fast);
});
// Output (one per second):
// 0 'a' (after 1s)
// 1 'b' (after 2s)
// 2 'c' (after 3s)
Common Use Cases
Parallel Requests with Ordering
import { zip } from 'rxjs';
import { ajax } from 'rxjs/ajax';
const requests$ = zip(
ajax.getJSON('/api/user/1'),
ajax.getJSON('/api/user/2'),
ajax.getJSON('/api/user/3')
);
requests$.subscribe(([user1, user2, user3]) => {
console.log('Users:', user1, user2, user3);
});
Coordinate Multiple Streams
import { zip, fromEvent } from 'rxjs';
const clicks$ = fromEvent(document, 'click');
const keys$ = fromEvent(document, 'keypress');
zip(clicks$, keys$).subscribe(([clickEvent, keyEvent]) => {
console.log('Click then key!');
});
Comparison with Other Operators
zip vs combineLatest: zip pairs by index, combineLatest uses latest values.zip vs forkJoin: zip emits multiple times, forkJoin emits once when all complete.
- combineLatest - Combine latest values
- forkJoin - Wait for all to complete
- merge - Merge all values
- withLatestFrom - Sample latest from other Observables
See Also