DEV Community

Cover image for First & Last Operators: Getting Started with RxJS - V
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on • Edited on

First & Last Operators: Getting Started with RxJS - V

I recently came across MkDocs-Material by Martin Donath, a fantastic open-source project with over 22k GitHub stars.

It’s an incredible contribution to the community, making documentation hosting effortless.

While exploring it, I got curious about how such a large project achieves reactiveness.

The stack is mostly HTML, SCSS, Preact, RxJS, and a few workers, and I saw this as the perfect opportunity to dive into RxJS—especially how it utilizes Observables and other advanced patterns.

RxJS offers a wide variety of operators that help in handling observables efficiently.

Among them, the first and last operators allow you to pick specific values from an observable stream.

Understanding these operators can be crucial when dealing with data streams where only the first or last emitted value matters.

The first Operator: Picking the First Emission

The first operator extracts only the very first value emitted by an observable and then completes.

Example:

import { of, first } from 'rxjs';

const numbers$ = of(-3, -2, -1, 0, 1, 2, 3);
numbers$.pipe(
  first()
).subscribe(value => console.log(value));

// Output: -3
Enter fullscreen mode Exit fullscreen mode

In this case, first() ensures that only -3, the first value emitted by numbers$, is logged.

Applying Conditions

You can also pass a predicate function to first(), which selects the first value that satisfies a condition:

numbers$.pipe(
  first(value => value > 0)
).subscribe(value => console.log(value));

// Output: 1
Enter fullscreen mode Exit fullscreen mode

The last Operator: Picking the Last Emission

The last operator extracts only the last emitted value before the observable completes.

Example:

import { last } from 'rxjs';

numbers$.pipe(
  last()
).subscribe(value => console.log(value));

// Output: 3
Enter fullscreen mode Exit fullscreen mode

Here, last() ensures that only 3, the last value from numbers$, is logged.

Applying Conditions

Just like first(), you can pass a condition to last():

numbers$.pipe(
  last(value => value < 0)
).subscribe(value => console.log(value));

// Output: -1
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

  • Fetching API data: If an API response contains an array of data and you only need the first or last item.
  • Processing user input: Selecting the first user interaction from a stream of clicks.
  • Handling data streams: Picking the first or last reading from a series of sensor measurements.

Bonus: Using forkJoin for Combining Observables

If you need to combine multiple observables and only emit the final values, forkJoin is your go-to operator.

Example:

import { forkJoin, of, delay } from 'rxjs';

const obs1$ = of('rainbows').pipe(delay(2000));
const obs2$ = of('unicorns').pipe(delay(2000));

forkJoin([obs1$, obs2$]).subscribe(values => console.log(values));

// Output (after 2s): ['rainbows', 'unicorns']
Enter fullscreen mode Exit fullscreen mode

This ensures that the subscription only receives values after both observables have completed.


Handling Errors with catchError and retry

Error handling is essential in reactive programming. The catchError operator allows graceful handling of errors, while retry lets you reattempt a failed observable sequence.

Example:

import { throwError, catchError, retry } from 'rxjs';

const faulty$ = throwError(() => new Error('Something went wrong!'));

faulty$.pipe(
  retry(2),
  catchError(err => of(`Error caught: ${err.message}`))
).subscribe(value => console.log(value));

// Output (after 2 retries): Error caught: Something went wrong!
Enter fullscreen mode Exit fullscreen mode

Conclusion

The first and last operators are simple yet powerful tools for extracting key values from an observable stream.

Whether you're handling API responses, processing user interactions, or managing error scenarios, these operators come in handy.

Mastering them, along with forkJoin, catchError, and retry, ensures you can build robust, efficient reactive applications.

Image description

I’ll be sharing more learnings, so stick around/follow for more deep dives into RxJS and beyond! 🚀

While exploring mkdocs-material implementation, I've been learning how to adapt these techniques for LiveAPI, a product I've been passionately working on for quite a while.

With LiveAPI, you can quickly generate interactive API documentation that allows users to execute APIs directly from the browser.

Image description

If you’re tired of manually creating docs for your APIs, this tool might just make your life easier.

Top comments (0)