So far, we have encountered some RxJS operators that we used to wrap different data sources to create Observables, like from
and of
, but there is more to it. In this section, you will be introduced to the most commonly used creational operators. In the end, we will provide a documentation reference for some other creational operators.
from
The from
operator can be used to wrap an array, a promise, or an iterable into an Observable. The code given below demonstrates how to wrap an array of strings into an Observable. Every new subscriber will be able to consume all the data from the data source.
const { from } = require('rxjs');const DATA_SOURCE = [ 'String 1', 'String 2', 'Yet another string', 'I am the last string' ];const observable$ = from(DATA_SOURCE)observable$.subscribe(console.log)
of
of
is another creational operator that creates Observable from a sequence of data. The difference between from
and of
is that from
creates an Observable from an iterable, which can be an array.
Notice how the entire array is emitted in the first example, when provided as a single parameter to the of
operator, compared to the sequence of items emitted in the second example.
const { of } = require('rxjs');const DATA_SOURCE = [ 'String 1', 'String 2', 'Yet another string', 'I am the last string' ];const observableArray$ = of(DATA_SOURCE)console.log("Array data source")observableArray$.subscribe(console.log)console.log("\n")console.log("Sequence data source")const observableSequence$ = of('String 1', 'String 2', 'Yet another string', 'I am the last string')observableSequence$.subscribe(console.log)
range
range
is a very useful operator that emits all numbers from a given range
in a sequence. This is very useful if we want to iterate an array in a reactive fashion.
The following example demonstrates the creation of a range
, which includes the starting and ending index of the given array.
const { range } = require('rxjs');const data = ['item 1', 'item 2', 'item 3']const observableRange$ = range(0, data.length)observableRange$.subscribe(index => console.log(data[index]))
Interval
As the name suggests, this operator is able to emit values at regular intervals. We will use this operator later in this course to show interactive timed notifications, but for now, let’s stick with a simple example.
Note: We need to unsubscribe from the Observable after a specific time (one second in this case) since the Observable will constantly produce new values every 100ms.
const { interval } = require('rxjs');const fastObservable$ = interval(100)const subscription = fastObservable$.subscribe(() => console.log('100ms have passed'))setTimeout(() => {subscription.unsubscribe();console.log('1 second has passed');}, 1000)
Timer
Using the previous example with interval
as a starting point, suppose that we would want the values to start emitting at regular intervals only after one second has passed. We can achieve that with the timer
operator. The following example indicates that the Observable will start producing values after 1000ms and will produce values at regular intervals of 100ms.
This operator can be useful in some cases where you would want values produced over regular intervals, which will start after a certain amount of time has passed.
const { timer } = require('rxjs');const fastObservable$ = timer(1000, 100)const subscription = fastObservable$.subscribe(() => console.log('100ms have passed'))setTimeout(() => {subscription.unsubscribe();console.log('1 second has passed');}, 1000)
defer
defer
is an operator that takes a function as an argument and executes it only when an Observer subscribes to it. This is very useful for time-related operations, e.g., getting the current time of execution.
The following examples illustrate the usage of defer
when the function that is passed to the Observable doesn’t return anything and when it returns an Observable, represented by Example 1 and Example 2, respectively. Remember, the function passed to defer
must return an Observable in order to remain within the concept of pure functions.
const { defer, of } = require('rxjs');// Example 1const functionToBeExecutedOnSubscribe = () => console.log('exectuing now')const observable1$ = defer(functionToBeExecutedOnSubscribe)observable1$.subscribe()// Example 2const functionToBeExecutedOnSubscribeReturnsObservable = () => of('val1', 'val2')const observable2$ = defer(functionToBeExecutedOnSubscribeReturnsObservable)observable2$.subscribe(console.log)
fromEvent
The most useful operator when building complex SPAs is fromEvent
. You would use this operator to wrap mouse or keyboard events into Observables, as shown below:
const keysDown$ = fromEvent(document, 'keydown')
keysDown$.subscribe(console.log)
These creational operators cover most of your needs while applying the reactive paradigm to your JS application. However, there are additional creational operators that you may find useful.
You can find them here, along with other RxJS operators, which we will discuss in the next lessons.