Observable

An observable is a stream object, which has methods for interacting with that stream.

  • because it is a stream, the data it represents is naturally asynchronous. Therefore, we interact with the observable in an asynchronous way, and the observable listens to a producer of data.

The problem is this: we can consider an array where we already know all the values as eager, and an array that receives values (ie. increases length) at a set interval (1s) as lazy. Normally, we perform data processing in an eager way, since the data is processed immediately as it's received, which is instant. What if we are in a position where the array grows over time? It would be beneficial if we could call a method on an array value as it enters the array. In this sense, we need to subscribe to the array to execute a method when the array grows.

observables are conceptually similar to a fancy event emitter.

There are 2 sides to an observable: producer and consumer

  • Producer - adds to the array
    • ex. button clicks add that click event to the array
  • Consumer - calls the function on the new array item
    • ex. calls console.log in response to the new click event

Just as promises abstract time away from our concern for a single asynchronous operation, observables abstract time away from a set of data (eg. array)

If you combine the functionality of an Observer and an Observable, you get a Subject

  • subject: you can send to it and receive from it.

  • Observable: you can receive from it only.

  • each operator on an Observable returns a new Observable, meaning they are chainable (this is known as a stream)

  • A map(..) on an array runs its mapping function once for each value currently in the array, putting all the mapped values in the outcome array. A map(..) on an Observable runs its mapping function once for each value, whenever it comes in, and pushes all the mapped values to the output Observable.

Characteristics

  • They are time-independent (ie. lazy)
  • They are mostly used in asynchronous data streams, like web sockets or multiple concurrent api calls
  • An Observer subscribes (ie. is consumer) to an Observable
    • an observer is a collection of callbacks

Differences with other async approaches

The following table shows what role observables fulfill. When we want to get a single value for a synchronous action, we set the value to a variable. When we want to get a single value for an async action, we use promises. When we want to get the value for an array synchronously, we use an array. Finally, when we want to get the value of an array of values asynchronously, we use observables.

  • Rxjs has a function lastValueFrom, which converts an observable to a promise
    • when we call that function, it will subscribe to the observable. Once it is complete, it resolves the returned promise with the last value from the observed stream.
syncasync
singlevariablepromise
collectionarrayobservable
  • while promises handle data processing in an eager way, an observable does it lazily. That is, it sits around waiting for the event to happen, then it will respond.
  • In a traditional workflow, we take a pull approach by calling a function to do something for us. That is, the consumer decides when it's going to get the data. Functions are naturally pull, because whoever uses the function is "pulling" out a single return value from its call.

Observables are like arrays because they represent a collection of events but are also like promises as they’re asynchronous: each event in the collection arrives at some indeterminate point in the future.

  • This is distinct from a collection of promises (like Promise.all) as an observable can handle an arbitrary number of events, and a promise can only track one thing.

Observables are lazy Push collections of multiple values. They fill the missing spot in the following table:

SingleMultiple
PullFunctionIterator
PushPromiseObservable
  • They push with .next()

An observable can be used to model clicks of a button. It represents all the clicks that will happen over the application’s lifetime, but the clicks will happen at some point in the future that we can’t predict.

let myObs$ = clicksOnButton(myButton);

When we create an observable, we add subscribers (ie. observers) to it

{
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  setTimeout(() => {
    subscriber.next(4);
    subscriber.complete();
  }, 1000);
};

While an observable is by design a type of stream, consider the different scales at which a stream like Kafka sits compares to where observables sit.

  • A Kafka stream (ie. topic) has potentially many subscribers to its set of data. Many are consuming the same set.

  • An observable stream is local to one set of data for one user (ie. they are said to be cold observables).

    • ex. Think of movie data of Netflix represented as an observable. When you press play, you are effectively subscribing to an observable. You are the only subscriber of this stream (unicast) and have full control of when it starts/stops. When someone in a different household watches the same movie as you a brand new observable is created and they are subscribed to it.
  • If you wanted to subscribe to the reactive way of programming, then you could just "observable all the things"

  • Observables are cancellable.

Example: Weather report

Consider that if you want to know the weather for the day, you can either look it up to get a single response, or you can turn on your radio and get a constant stream of updates. That is, as long as you are subscribed to it (ie. as long as the radio is turned on), you will get all the latest information about the weather.

  • While the weather itself is observable, in this example the user is actually subscribed to the radio, which is another observable.
  • Behind that, the radio gets its data from a weatherman, which is another observable.
  • Even more beyond that, the weatherman gets his data from a meteorologist report, yet another observable (here we say the data received by the weatherman is a function of the data from the meteorologist report).
  • the meteorologist report gets its data from the instruments (baromoter, wind gauge etc.), which is another observable,
  • finally, the instruments get their data from the weather itself, yet another observable.
  • all in all this whole sequence shows at least 5 observables. The radio is the output observable, and the weather itself is the source observable. All the observables in between represent the PIPE FUNCTION.

Backlinks