RxJS Mastery – #35 pairwise

RxJS pairwise lesson title

The RxJS pairwise operator groups the latest two values and emits them as a pair in an array. Therefore all but the first and last value of the source Observable appear twice in the final submission.

RxJS pairwise always creates pairs

The pairwise operator combines during the nth submission of the source Observable the current and previous value of the source Observable. Therefore it emits an array in the form of [n-1, n]. Let’s have a look at a basic example below:

of(1,2,3,4).pipe(
    pairwise()
).subscribe(console.log);

// [1,2]
// [2,3]
// [3,4]

A source Observable with “length” 4 will lead to 3 pairs. Importantly, pairwise will only start emitting once it received a second value (number 2 in above example). The number 2 is then again combined in a pair with the number 3 and therefore emitted twice.

RxJS pairwise just completes if there are no pairs

As mentioned above the pairwise operator always waits for pairs. If only one or no value is emitted by the source Observable then the resulting Observable just completes:

const result$ = of(1).pipe(
    pairwise()
);

expectObservable(result$).toBe('|');

Calculate the distance between two consecutive clicks

The RxJS pairwise always remembers the (n-1)th value of the source Observable when the nth value is emitted. Therefore we can elegantly calculate the distance between consecutive clicks (example from rxjs.dev)

import { fromEvent, pairwise, map } from 'rxjs';

const clicks$ = fromEvent<PointerEvent>(document, 'click');
const pairs$ = clicks$.pipe(pairwise());
const distance$ = pairs$.pipe(
  map(([first, second]) => {
    const x0 = first.clientX;
    const y0 = first.clientY;
    const x1 = second.clientX;
    const y1 = second.clientY;
    return Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
  })
);

distance$.subscribe(x => console.log(x));

RxJS pairwise vs. bufferCount

The following example also emits pairs by combining the two operators bufferCount and filter:

of(1,2,3,4).pipe(
    bufferCount(2, 1),
    filter(arr => arr.length === 2),
).subscribe(console.log);

So, where is the difference then? First, pairwise is simpler to use. Second, according to this discussion it is more performant.

Exercise for the RxJS pairwise operator 💪

Implement a triplet operator considering the values n, n-1, n-2 (similar behaviour as pairwise). Which other operators help you?

As always the code examples and exercise solution can be found on GitHub.