Exploring The Major Concepts in RxJS

This topic describes the major Reactive Extensions for JavaScript (Rx) objects used to represent observable sequences and subscribe to them.

The Observable / Observer objects are available in the core distribution of RxJS.

Observable / Observer

Rx exposes asynchronous and event-based data sources as push-based, observable sequences abstracted by the Observable object in the core distribution of RxJS. It represents a data source that can be observed, meaning that it can send data to anyone who is interested.

As described in What is RxJS, the other half of the push model is represented by the Observer object, which represents an observer who registers an interest through a subscription. Items are subsequently handed to the observer from the observable sequence to which it subscribes.

In order to receive notifications from an observable collection, you use the subscribe method of Observable to hand it an Observer object. In return for this observer, the subscribe method returns a Disposable object that acts as a handle for the subscription. This allows you to clean up the subscription after you are done. Calling dispose on this object detaches the observer from the source so that notifications are no longer delivered. As you can infer, in RxJS you do not need to explicitly unsubscribe from an event as in the common JavaScript event model.

Observers support three publication events, reflected by the object's methods. The onNext can be called zero or more times, when the observable data source has data available. For example, an observable data source used for mouse move events can send out an event object every time the mouse has moved. The other two methods are used to indicate completion or errors.

The following lists the Observable / Observer objects in addition to the Disposable object.

/**
 * Defines a method to release allocated resources.
 */
function Disposable() { }

/**
 * Performs application-defined tasks associated with freeing, releasing, or resetting resources.
 */
Disposable.prototype.dispose =  () => { ... }

/**
 * Defines a provider for push-based notification.
 */
function Observable() { }

/**
 * Notifies the provider that an observer is to receive notifications.
 *
 * @param {Observer} observer The object that is to receive notifications.
 * @returns {Disposable} A reference to disposable that allows observers to stop receiving notifications before the provider has finished sending them.
 */
Observable.prototype.subscribe =  observer => { ... }

/**
 * Provides a mechanism for receiving push-based notifications.
 */
function Observer() { }

/**
 * Provides the observer with new data.
 *
 * @param {Any} value The current notification information.
 */
Observer.prototype.onNext = value => { ... };

/**
 * Notifies the observer that the provider has experienced an error condition.
 *
 * @param {Error} error An object that provides additional information about the error.
 */
Observer.prototype.onError = error => { ... };

/**
 * Notifies the observer that the provider has finished sending push-based notifications.
 */
Observer.prototype.onCompleted = () => { ... };

RxJS also provides subscribe capabilities so that you can avoid implementing the Observer object yourself. For each publication event (onNext, onError, onCompleted) of an observable sequence, you can specify a function that will be invoked, as shown in the following example. If you do not specify an action for an event, the default behavior will occur.

// Creates an observable sequence of 5 integers, starting from 1
var source = Rx.Observable.range(1, 5);

// Prints out each item
var subscription = source.subscribe(
    x => console.log('onNext: ' + x),
    e => console.log('onError: ' + e.message),
    () => console.log('onCompleted'));

// => onNext: 1
// => onNext: 2
// => onNext: 3
// => onNext: 4
// => onNext: 5
// => onCompleted

You can treat the observable sequence (such as a sequence of mouse-over events) as if it were a normal collection. Thus you can write queries over the collection to do things like filtering, grouping, composing, etc. To make observable sequences more useful, the RxJS libraries provide many factory operators so that you do not need to implement any of these on your own. This will be covered in the Querying Observable Sequences topic.

Caution:

You do not need to implement the Observable/Observer objects yourself. Rx provides internal implementations of these interfaces for you and exposes them through various extension methods provided by the Observable and Observer types. See the Creating and Querying Observable Sequences topic for more information.

See Also

Concepts

Other Resources