RxJS Mastery – #13 generate

The generate operator uses a loop like approach to generate values for emission.

RxJS generate explained 🎓

The following code will for example output the numbers from 1 to 5 as single values.

const numbers$ = generate(1, x => x <= 5, x => x + 1, x => x, undefined);

numbers$.subscribe({ next: console.log });

In above example we see that the generate function accepts 5 parameters. If we have a closer look we see that the function is defined as follows:

generate<T, S>(
    initialStateOrOptions: S | GenerateOptions<T, S>, 
    condition?: ConditionFunc<S>, 
    iterate?: IterateFunc<S>, 
    resultSelectorOrScheduler?: SchedulerLike | ResultFunc<S, T>, 
    scheduler?: SchedulerLike
): Observable<T>

The first three arguments look familiar if you know the for loop. The two other are RxJS specific but you should also know them if you have read the other articles about RxJS.

  • initialStateOrOptions define the initial value
  • condition tells the generate function when to stop generating values
  • iterate is the function applied on the initial value and its successors
  • once iterate has generated a next value the resultSelectorOrScheduler allows to apply a map function before outputting the value
  • finally the scheduler controls the emission of the values (see RxJS Schedulers).

What problems does the RxJS generate operator solve? 🚧

The generate function accepts arguments similar to a traditional for loop. Therefore it’s obviously helpful if you have values provided by a for loop that you want to have as Observable. When using the operator you can clearly define when the submission ends.

How to test the generate operator🚦

Once again the rxjs marbles testing approach gives us an easy way to verify the output:

it('should test the generation of numbers 1 to 5', () => {
    testScheduler.run((helpers) => {
        const { expectObservable } = helpers;

        const numbers$ = generate(1, x => x <= 5, x => x + 1, x => x, asapScheduler);

        expectObservable(numbers$).toBe('(abcde|)', {a: 1, b: 2, c: 3, d: 4, e: 5});

In the example we also clearly see that generate emits the values at the same time but as separate values. As soon as the condition does not hold anymore (x <= 5) the generate function stops and the Observable completes.

Exercise for the generate operator 💪

Use generate to create the fibonacci numbers from 1 to 21.