Introduction to RxJS and using it properly in Angular
Backgroud
- Programming with asynchronous data streams
- Improves user experience (handling real-time events and interactive experience)
What is Reactive Programming?
Need of observables
getData(() => {
getMoreData(() => {
getEvenMoreData() => {
}
})
})
getData()
.then(getMoreData)
.then(getEvenMoreData)
Callback hell
Promises

- Can emit multiple values
- Can be cancelled
- Can Retry
- Are Lazy
RxJS: The ReactiveX library for JavaScript
- API developed by http://reactivex.io/
- Gives support for asynchronous programming
with observable streams
Observables
-
Can define both the setup and teardown aspects of asynchronous behavior
-
Has a subscribe method subscribe(fnValue, fnError, fnComplete)
let stream$ = Rx.Observable.create((observer) => {
observer.next(1);
observer.error('error message');
observer.complete();
});
stream$.subscribe((data) => {
console.log('Data', data);
},
(error) => {
console.log('Error', error);
}
// 1
Always clean up
Unsubscribe
- To avoid memory leaks
- Can be done explicitly stream$.unsubscribe()
- Can be done implicitly with stream$.takeWhile()
Angular
- Best time to unsubscribe is when your component is destroyed.
- Do it inside ngOnDestroy()
Creating observables
.fromEvent() | |
.from() | |
.fromPromise() |
we can create observable from any type of data stream
const btnStream$ = Rx.Observable.fromEvent(btn, 'click');
const arrayStream$ = Rx.Observable.from([1,2,3]);
const promiseStream$ = Rx.Observable.fromPromise(myPromise);
Operators
- Creation type operator
- Synchronous in nature
of
let stream$ = Rx.Observable.of(1,2,3,4,5)
filter
- Filters out values from being emitted
let stream$ =
Rx.Observable
.of(1,2,3,4,5)
.filter((value) => {
return value % 2 === 0;
})
// 2,4
Used to debug observables
do
let stream$ = Rx.Observable
.of(1,2,3,4,5)
.do((value) => {
console.log('do',value)
})
.filter((value) => {
return value % 2 === 0;
})
stream$.subscribe((value) => {
console.log('value', value)
})
// do: 1,do : 2, do : 3, do : 4, do: 5
// value : 2, 4
Other commonly used operators
//delay()
var start = new Date();
let stream$ = Rx.Observable.interval(500).take(3);
stream$
.delay(300)
.subscribe((x) => {
console.log('val',x);
console.log( new Date() - start );
})
//0 800ms, 1 1300ms,2 1800ms
//sample
const btn = document.getElementById('btnIgnore');
var start = new Date();
const input$ = Rx.Observable
.fromEvent(btn, 'click')
.sampleTime(2000);
input$.subscribe(val => {
console.log(val, new Date() - start);
});
//debounceTime()
const input = document.getElementById('input');
const example = Rx.Observable
.fromEvent(input, 'keyup')
.map(i => i.currentTarget.value);
//wait 0.5s, between keyups, throw away all other values
const debouncedInput = example.debounceTime(500);
const subscribe = debouncedInput.subscribe(val => {
console.log(`Debounced Input: ${val}`);
});
Subject
- Has both the behaviour from an Observer and an Observable
Type of subjects:
Replay Subject
new Rx.ReplaySubject([bufferSize], [windowSize], [scheduler]);
let replaySubject = new Rx.ReplaySubject( 2 );
replaySubject.next( 0 );
replaySubject.next( 1 );
replaySubject.next( 2 );
let replaySubscription = replaySubject.subscribe((value) => {
console.log('replay subscription', value);
});
// 1, 2
Async Subject
let asyncSubject = new Rx.AsyncSubject();
asyncSubject.subscribe(
(value) => console.log('async subject', value),
(error) => console.error('async error', error),
() => console.log('async completed')
);
asyncSubject.next( 1 );
asyncSubject.next( 2 );
asyncSubject( 3 )
asyncSubject.error('err')
asyncSubject.complete()
// will emit 'err' as the last action
Behaviour Subject
let behaviorSubject = new Rx.BehaviorSubject(42);
behaviorSubject.subscribe((value) => console.log('behaviour subject',value) );
console.log('Behaviour current value',behaviorSubject.getValue());
behaviorSubject.next(1);
console.log('Behaviour current value',behaviorSubject.getValue());
behaviorSubject.next(2);
console.log('Behaviour current value',behaviorSubject.getValue());
behaviorSubject.next(3);
console.log('Behaviour current value',behaviorSubject.getValue());
// emits 42
// current value 42
// emits 1
// current value 1
// emits 2
// current value 2
// emits 3
// current value 3
Hot n cold Observables
let obs = Rx.Observable
.create(observer => observer.next(Date.now()));
obs.subscribe(v => console.log("1st: " + v));
obs.subscribe(v => console.log("2nd: " + v));
// 1st subscriber: 1465990942935
// 2nd subscriber: 1465990942936
- creates the producer
- activates the producer
- starts listening to the producer
- shares a reference to a producer
- starts listening to the producer
Cold observable
Hot observable
let obs = Rx.Observable
.create(observer => observer.next(Date.now()))
.publish();
obs.subscribe(v => console.log("1st: " + v));
obs.subscribe(v => console.log("2nd: " + v));
obs.connect();
// 1st subscriber: 1465990942936
// 2nd subscriber: 1465990942936
RxJS in Angular
Passing observables to the view
import { Component } from '@angular/core'
import { Observable } from 'rxjs/Rx'
@Component({
selector: 'my-app',
template: `
<ul>
<li *ngFor="let item of items | async">
</li>
</ul>
`
})
export class AppComponent {
public items = Observable.of([1, 2, 3])
}
RxJS in Angular
Using with http
import { Injectable } from '@angular/core'
import { Http } from '@angular/http'
import { Observable } from 'rxjs/Rx'
import 'rxjs/add/operator/map'
@Injectable()
export class RepoService {
constructor(private _http: Http) {}
getReposForUser(user: string): Observable<any> {
return this._http
.get(`https://api.github.com/users/${user}/repos`)
.map((res: any) => res.json())
}
}
RxJS in Angular
Communication between components
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
@Component({
selector: 'my-score',
template: 'Summary: ',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ScoreComponent {
@Input() public score: number
}
@Component({
selector: 'my-app',
template: `
<button (click)="counter$.next(1)">
Up Vote
</button>
<my-score [score]="counter$ | async"></my-score>
`,
})
export class AppComponent {
public counter$: Observable<number> = new Subject<number>()
.scan((acc: number, current: number): number => acc + current)
}
Thank you :)
RxJS using it properly in Angular
By Zenab Saleem
RxJS using it properly in Angular
- 1,018