Observable

Limited availability

This feature is not Baseline because it does not work in some of the most widely-used browsers.

Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.

The Observable interface of the Observable API represents a stream of values that can be subscribed to.

Observable objects (commonly called observables) can be thought of as more powerful event listeners that integrate with EventTarget. They improve event handling code in a similar way to how promises improved on callbacks, simplifying code by reducing the need for nested blocks.

Observables have several methods that return a new observable, and these methods can be chained together to create a pipeline to precisely control the stream of values as desired.

There are three main ways to obtain observables:

Constructor

Observable()

Creates a new Observable object instance.

Static methods

from()

Returns an observable converted from a promise, iterable, or async iterable, or returns an existing observable unchanged.

Instance methods

subscribe()

Subscribes to a value stream, most commonly a stream of events.

Observable-returning instance methods

catch()

Returns a new observable that replaces an error from the source observable with values from another observable.

drop()

Returns a new observable that skips the given number of values at the start of the source observable.

filter()

Returns a new observable that emits only those values of the source observable for which the provided callback function returns a truthy value.

finally()

Returns a new observable that mirrors the source observable and calls a callback when its subscription ends.

flatMap()

Returns a new observable that maps each value of the source observable to an inner observable and emits the inner observables' values sequentially.

inspect()

Returns a new observable that mirrors the source observable and calls callbacks to inspect its values and subscription lifecycle.

map()

Returns a new observable that emits the values of the source observable, each transformed by a mapping function.

switchMap()

Returns a new observable that maps each value of the source observable to an inner observable and emits values from only the latest inner observable.

take()

Returns a new observable that emits the given number of values from the start of the source observable and then completes.

takeUntil()

Returns a new observable that emits values from the source observable until another observable emits a value or errors.

Promise-returning instance methods

every()

Returns a promise that fulfills with a boolean indicating whether every value emitted by the source observable satisfies the provided testing function.

find()

Returns a promise that fulfills with the first value emitted by the source observable that satisfies the provided testing function, or undefined if the source completes without a match.

first()

Returns a promise that fulfills with the first value emitted by the source observable.

forEach()

Returns a promise that fulfills with undefined when the source observable completes, after executing a callback for each emitted value.

last()

Returns a promise that fulfills with the last value emitted by the source observable.

reduce()

Returns a promise that fulfills with a single value obtained by combining the source observable's values using a reducer function.

some()

Returns a promise that fulfills with a boolean indicating whether any value emitted by the source observable satisfies the provided testing function.

toArray()

Returns a promise that fulfills with a new array containing the source observable's values in the order they were emitted.

Examples

Obtaining an observable from an EventTarget

This example displays the mouse coordinates in a <p> element only when the pointer moves over a <div> element. The pipeline filters the body's mousemove events by their target and extracts the coordinates. For the page setup, see Transforming an observable.

js
const outputElem = document.querySelector("p");

document.body
  .when("mousemove")
  .filter((e) => e.target.matches("div"))
  .map((e) => ({ x: e.clientX, y: e.clientY }))
  .subscribe((p) => {
    outputElem.textContent = `${p.x},${p.y}`;
  });

For more working examples, see Using observables.

Creating a custom observable

This function creates an observable that emits an increasing count at a specified interval. It completes on the interval after the requested number of values has been emitted. The teardown callback clears the interval when the subscription ends, including when all observers unsubscribe. For a button-driven counter using this producer, see Teardown.

Note: This shared-subscription behavior may change. A proposal to give each observer its own Subscriber would make each subscription start a separate execution instead of reusing an active subscription.

js
function makeTimer(timerInterval, iterations = Infinity) {
  return new Observable((subscriber) => {
    let i = 1;
    const interval = setInterval(() => {
      if (i === iterations + 1) {
        subscriber.complete();
      } else {
        subscriber.next(i);
      }
      i++;
    }, timerInterval);
    subscriber.addTeardown(() => {
      clearInterval(interval);
    });
  });
}

For more working examples, see Creating custom observables.

Specifications

Specification
Observable
# observable-api

Browser compatibility

See also