RxJS Mastery – #34 mergeScan

RxJS mergeScan lesson title

The RxJS mergeScan operator applies an accumulator function that returns an Observable. This accumulator function is similar to the one in reduce.

RxJS mergeScan can sum up values

Also here we start with a basic example, using of(), that isn’t making too much sense in a real context. But it demonstrates well how mergeScan is used:

const result$ = of(1,2,3,4).pipe(
    mergeScan((acc, cur) => of(acc + cur), 0)
);

result$.subscribe((v) => console.info(v));
// 1
// 3
// 6
// 10

The mergeScan operator returns an Observable created from the sum of the accumulator and the current value. This Observable is merged into the output.

Count the seconds between events like keyDown/keyUp

With mergeScan we can accumulate the seconds between keyDown and keyUp. Of course this needs some helping functions:

const keyDown$ = fromEvent(document, 'keydown');
const keyUp$ = fromEvent(document, 'keyup');

const duration = document.getElementById('duration');

keyDown$.pipe(
    mergeScan((acc, curr) => {
        return interval(1000).pipe(
            scan((a, _) => ++a, 0),
            map((val) => val + acc),
            takeUntil(keyUp$)
        );
    }, 0)
).subscribe(val => (duration.innerHTML = `${val}s`));

An inner Observable based on interval (1s) is started. This helps us to count the seconds. The counting stops as soon as the key is lifted thanks to takeUntil(keyUp$). In the end the result shows how many seconds the key was pressed down:

Exercise for the RxJS mergeScan operator 💪

Use the following skeleton to implement a continuous loading and content appending with mergeScan. The content can just be concatenated with javascript’s concat.

interface Page {
    content: string;
    next: number;
}

interface TotalContent {
    content: string;
    loaded: number;
}

const paginatedHttpService = {
    getPage: (page: number): Observable<Page> => of({content: `Lorem ipsum on page ${page}`, next: page + 1})
};

The final expected output is:

{ 
    content: ' Lorem ipsum on page 1',
    loaded: 1 
}

{   
    content: ' Lorem ipsum on page 1 Lorem ipsum on page 2', 
    loaded: 2 
}

{
    content: ' Lorem ipsum on page 1 Lorem ipsum on page 2 Lorem ipsum on page 3',
    loaded: 3
}

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