Built-in Observable Creation
Parwinder 👨🏻💻
Posted on August 21, 2020
There are multiple ways of creating Observables in RxJS. We went through a couple of examples in the last few blog posts. We will go over a few more in this one. Some of them are essential, some based on time and some are what I consider meh ¯\(ツ)/¯.
Essentials!
of
of
creates an Observable from arguments. It does not do any flattening of arguments. If you pass it an Array-like argument, it will not iterate over the argument to generate Observable sequence. Instead, it will emit the whole argument.
import { of } from 'rxjs';
of(10, 20, 30)
.subscribe(
value => console.log(value) // 10 20 30 (3 log ouputs)
);
of([10, 20, 30])
.subscribe(
value => console.log(value) // [10, 20, 30] (1 log output, no looping of array)
);
from
from
creates an Observable from Array, Array-like or iterable object. from
iterates over the argument to provide a sequence of emitted values unlike of
.
import { from } from 'rxjs/observable/from';
const array = [10, 20, 30, 40];
const numbers = from(array);
numbers.subscribe(
value => console.log(value)
);
As I said, it can work with more than Arrays. We will take an example where we pass it a generator function.
import { from } from 'rxjs/observable/from';
import { take } from 'rxjs/operators';
// starts with 2
// doubles the number between yields
function* generator() {
let i = 2;
while (i <= 32) {
yield i;
i = i * 2;
}
}
const iterator = generator();
const numbers = from(iterator);
numbers.subscribe(x => console.log(x)); // 2 4 8 16 32
throw
throw
creates an Observable that only emits an error and no items.
import { _throw } from 'rxjs/observable/throw';
const observable = _throw(new Error("Woops"));
observable.subscribe(
x => console.log(x),
e => console.error(e) // Error: Woops
);
Since throw
is reserved in JavaScript, RxJS uses _throw
. RxJS 6 has introduced throwError now!
range
range
creates an Observable that emits a sequence of numbers between a range. We provide the start integer and the number of sequential integers to generate.
import { range } from 'rxjs/observable/range';
const numbers = range(1, 10);
numbers.subscribe(x => console.log(x));
The above example starts at 1 and prints the next ten numbers (including 1). So output is 1, 2, 3, 4, 5, 6, 7, 8, 9, 10.
Time based
interval
We have used interval
in the last few blog posts. It creates an Observables that provides sequential numbers at specified time intervals.
import { interval } from 'rxjs';
const observable = interval(1000);
observable.subscribe(
value => console.log(value)
// 1 2 3 4 5 6... so on till infinity
// every value is logged 1 second apart
);
timer
timer
produces an Observable after x
amount of time. It keeps producing sequential numbers with a time gap of y
milliseconds between each number. x
and y
are parameters timer
takes in.
import { timer } from 'rxjs/observable/timer';
const numbers = timer(3000, 1000);
numbers.subscribe(
value => console.log(value)
);
- The first parameter (3000) specifies how long to wait before emitting the first value.
-
numbers
Observable will start emitting values starting at 0 once 3 seconds have passed. - After logging 0, it will wait one second and print 1 and continue printing sequential numbers with a 1-second gap between them.
- The time gap between numbers is the second parameter.
- Both parameters are optional.
Without either parameters
import { timer } from 'rxjs/observable/timer';
const numbers = timer();
numbers.subscribe(
value => console.log(value)
);
If we do not specify either parameter (like above), the Observable will not wait to print the first value (0). Timer Observable will only print one value and immediately complete due to absence of time gap (second parameter).
Without interval
import { timer } from 'rxjs/observable/timer';
const numbers = timer(3000);
numbers.subscribe(
value => console.log(value)
);
The behavior of this Observable will be the same. Only one value (0) printed and then complete. The only difference is that the first value is printed after a wait of 3 seconds.
The difference between interval and timer is that we can specify the start time for timer.
Additional
empty
I see empty
as somewhat of an opposite to throw
or throwError
. empty
creates an Observable that generates no value (like throw
). Still, it emits a complete notification (unlike throw
that emits an error event).
import { empty } from 'rxjs/observable/empty';
empty().subscribe(
x => console.log(x),
e => console.log(e),
() => console.log('complete')
)
The only output is complete
.
empty
has been deprecated in favor of using EMPTY
constant.
never
never
has been deprecated in favor of NEVER
constant. NEVER
is an Observable that emits no items and never completes.
import { never } from 'rxjs/observable/never';
function logger() {
console.log('never called');
// never ouputs as logger is never called
}
never().subscribe(
x => console.log(x),
logger,
logger
)
defer
defer
is slightly tricky. It creates an Observable only when the Observer subscribes.
It also creates a new Observable for each Observer.
The new Observable is generated using an Observable factory function.
Every Observer subscribed to the Observable might think they are subscribed to the same Observable, but they are subscribing to their own Observable.
It delays the Observable creation until subscription. To illustrate the working of defer
and showcase the difference between defer
and of
, let's take an example.
import { of } from 'rxjs/observable/of';
import { defer } from 'rxjs/observable/defer';
const observable1 = of(new Date()); // will capture current date time
const observable2 = defer(() => of(new Date())); // will capture date time at the moment of subscription
console.log(new Date()); // 2020-07-06T06:19:25.368Z
observable1.subscribe(
date => console.log(date) // 2020-07-06T06:19:25.368Z
)
observable2.subscribe(
date => console.log(date) // 2020-07-06T06:19:25.369Z
)
Posted on August 21, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.