rxjs
before we start...
- playground
- best reference
- vizualized
How do you create a promise?
const promise = new Promise((resolve, reject) => {
... long running code
resolve(data);
});
How do you create an observable?
const obs$ = new Observable(observer => {
... long running code
observer.next(data);
observer.next(data);
observer.complete();
});
Observables are lazy
Compared to promises
let obs$ = new Observable(() =>
console.log('work');
);
obs$.subscribe()
obs$.toPromise()
new Promise(() =>
console.log('work');
);
How do you error a promise?
const promise = new Promise((resolve, reject) => {
... long running code
reject('It went wrong');
});
How do you error an observable?
const obs$ = new Observable(observer => {
... long running code
observer.error('It went wrong');
});
.subscribe()
obs$.subscribe(onTick, onError, onComplete);
Exercise
- create a function which creates observable emitting a number every X ms
- 1,2,3,4...
Solution
function interval(time) {
return new Observable(observer => {
let counter = 1;
setInterval(() =>
observer.next(counter++);
}, time);
});
}
How to stop observing
const subscription = interval$.subscribe(onTick);
subscription.unsubscribe();
Q: What happens?
const subscription = createInterval$(1000)
.subscribe(val => console.log(val));
subscription.unsubscribe();
function createInterval$(time) {
return new Observable(observer => {
let counter = 1;
setInterval(() => {
console.log('XXX');
observer.next(counter++);
}, time);
});
}
Answer
const subscription = createInterval$(1000)
.subscribe(val => console.log(val));
subscription.unsubscribe();
function createInterval$(time) {
return new Observable(observer => {
let counter = 1;
const interval = setInterval(() => {
console.log('XXX');
observer.next(counter++);
}, time);
return () => clearInterval(interval);
});
}
Q: What happens?
let subscription = interval$.subscribe(onTick);
subscription = interval$.subscribe(onTick);
subscription.unsubscribe();
Other ways to create observable
- of(10, 12, 13)
- from([10, 12, 13])
- from(promise)
- fromEvent(document, 'click');
- interval(1000);
- empty() vs of()
- ...
timer(delay, interval)
Q: What happens?
const obs$ = from([1,2,3,4]);
console.log('one');
obs$.subscribe(
x => console.log(x),
null,
() => console.log('done')
);
console.log('two');
Operators
.pipe(...)
const derived$ = interval(1000).pipe(
map(x => x * 2)
);
derived$.subscribe(x => console.log(x));
Q: What happens?
const interval$ = interval(1000);
const derived$ = interval$.pipe(
map(x => x * 2)
);
interval$.subscribe(x => console.log(x));
Basic operators
take(5)
skip(3)
map(x => x*2)
filter(x => x % 2)
debounceTime(1000)
tap(console.log)
reduce((acc, curr) => ...)
[1,2,3,4,5].reduce((acc, curr) =>
acc + curr
);
Arrays
from([1,2,3,4,5]).pipe(reduce((acc, curr) =>
acc + curr
));
Observables
scan((acc, curr) => ...)
from([1,2,3,4,5]).pipe(scan((acc, curr) =>
acc + curr
, 0));
distinctUntilChanged()
shareReplay(1)
Exercise
- use basic operators to print
- output: 13, 17, 19, 23
- start with interval(200)
function isPrime(n) {
for (let i = 2; i < n; i++) {
if (n % i === 0) {
return false;
}
}
return n !== 1 && n !== 0;
}
Combining multiple observables
merge
- combines into one observables
const intervalOne$ = interval(1000);
const intervalTwo$ = interval(500);
merge(intervalOne$, intervalTwo$).subscribe(...)
combineLatest
- waits for all to emit
- emit each time after
const intervalOne$ = timer(1000, 1000);
const intervalTwo$ = timer(5000, 500);
combineLatest(intervalOne$, intervalTwo$).subscribe(...)
// 4, 0 <- depends on the first one to emit
// 5, 0
// 5, 1
// 5, 2
// 6, 3
// 6, 4
forkJoin
- waits for all to complete
- like Promise.all
const intervalOne$ = timer(1000, 1000).pipe(take(3));
const intervalTwo$ = timer(5000, 500).pipe(take(5));
forkJoin(intervalOne$, intervalTwo$).subscribe(...)
// 2, 4
switchMap
- switches to another observable
interval(5000).pipe(
switchMap(() => interval(500))
)
Exercise
- console.log random joke every 10 seconds
- use fetchJoke method
GET https://api.chucknorris.io/jokes/random
Subjects
What is a subject?
- observable
- you can make it emit anytime using next()
- similar to defer in Q
const subject = new Subject();
subject.subscribe(x => console.log(x));
subject.next(1);
subject.next(2);
Special types of subjects
- BehaviorSubject
- has getValue() for synchronous reading of the last value
- ReplaySubject
- emits the last value for every new subscription
Exercise
- create a subject
- create a button
- make the subject emit on every click
- console.log on each click by listening to Subject
<button (click)="methodInClass()">
click me
</button>
Final exercise
- reload joke every 5 seconds or when the button is clicked
- remember all loaded jokes (use scan)
Final exercise 2
- create a switcher
- has ON / OFF value
- button for turning on
- button for turning off
- button for toggling
rxjs
By Martin Nuc
rxjs
- 522