Wojciech Trawiński
Bydgoszcz, 2019
Slides
https://slides.com/wojtrawi/webdev-guild-rxjs
WebDeveloper working at Huuuge Games.
Passionate of Angular, RxJS, TypeScript and functional programming.
Owner of JavaScript everyday blog
Writer for Angular In Depth and Angular Love blogs
WebDeveloper working at Huuuge Games.
Passionate of Angular, RxJS, TypeScript and functional programming.
... a declarative programming paradigm
concerned with data streams and the propagation of change.
... a declarative programming paradigm
concerned with data streams and the propagation of change.
Object Oriented Programming
Reactive Programming
everything is a class
everything is a stream
In a nutshell:
In a nutshell:
Observable
Observer
subscribe
notifications
Types of observable notifications:
Types of observable notifications:
An observer may be interested in different kinds of notifications
and corresponding callbacks may be provided in the following ways:
Types of observable notifications:
An observer may be interested in different kinds of notifications
and corresponding callbacks may be provided in the following ways:
as object
interval(1000).subscribe({
next: console.log,
error: console.error,
complete: () => console.log('completed')
});
Types of observable notifications:
An observer may be interested in different kinds of notifications
and corresponding callbacks may be provided in the following ways:
as object
as successive arguments
interval(1000).subscribe(
console.log,
console.error,
() => console.log('completed')
);
interval(1000).subscribe({
next: console.log,
error: console.error,
complete: () => console.log('completed')
});
A representation of any set of values
over any amount of time
A representation of any set of values
over any amount of time
RxJS provides a large number of creational operators:
Streaming existing data
const numbers = [1, 2, 3];
const source$ = from(numbers);
source$.subscribe(console.log);
//console output: 1, 2, 3
Streaming existing data
Generating data
const numbers = [1, 2, 3];
const source$ = from(numbers);
source$.subscribe(console.log);
//console output: 1, 2, 3
const source$ = interval(5000);
source$.subscribe(console.log);
//console output (every 5s): 0, 1, 2, 3 ...
Streaming existing data
Generating data
Hooking into existing api
const numbers = [1, 2, 3];
const source$ = from(numbers);
source$.subscribe(console.log);
//console output: 1, 2, 3
const source$ = ajax('https://jsonplaceholder.typicode.com/users/1');
source$.subscribe(({ response }) => console.log(response));
//console output: object for user with id = 1
const source$ = interval(5000);
source$.subscribe(console.log);
//console output (every 5s): 0, 1, 2, 3 ...
Streaming existing data
Generating data
Hooking into existing api
Combining existing streams
const numbers = [1, 2, 3];
const source$ = from(numbers);
source$.subscribe(console.log);
//console output: 1, 2, 3
const user1$ = ajax('https://jsonplaceholder.typicode.com/users/1');
const user2$ = ajax('https://jsonplaceholder.typicode.com/users/2');
const users$ = merge(user1$, user2$);
users$.subscribe(({ response }) => console.log(response));
//console output: objects for users with 1 and 2 id
const source$ = interval(5000);
source$.subscribe(console.log);
//console output (every 5s): 0, 1, 2, 3 ...
const source$ = ajax('https://jsonplaceholder.typicode.com/users/1');
source$.subscribe(({ response }) => console.log(response));
//console output: object for user with id = 1
import { Observable } from 'rxjs';
const myAwesomeStream$ = new Observable(observer => {
let counter = 0;
const interval = setInterval(() => {
observer.next(counter++);
}, 1000);
return () => clearInterval(interval);
});
const mySubscription = myAwesomeStream$.subscribe(console.log);
setTimeout(() => {
mySubscription.unsubscribe();
}, 2500);
//console output: 0, 1
The callback passed to the Observable constructor will be called upon subscription with an observer passed to the subscribe method
Hot
Observable closes over notifications producer
…like watching a movie at the cinema:
Hot
Cold
Observable closes over notifications producer
…like watching a movie at the cinema:
Notifications producer created at subscription
…like watching a movie on Netflix:
… [multicasting] is the primary use case for Subjects in RxJS
… [multicasting] is the primary use case for Subjects in RxJS
Subject is both Observable and Observer
import { Subject, interval } from 'rxjs';
const source$ = interval(1000);
const mySubject = new Subject();
source$.subscribe(mySubject);
mySubject.subscribe(val => console.log(`#1 ${val}`));
setTimeout(() => {
mySubject.subscribe(val => console.log(`#2 ${val}`));
}, 5000);
cold
Subject
O1
O2
… [multicasting] is the primary use case for Subjects in RxJS
Subject is both Observable and Observer
Types of Subjects:
•Subject,
•BehaviorSubject,
•ReplaySubject,
•AsyncSubject.
cold
Subject
O1
O2
import { Subject, interval } from 'rxjs';
const source$ = interval(1000);
const mySubject = new Subject();
source$.subscribe(mySubject);
mySubject.subscribe(val => console.log(`#1 ${val}`));
setTimeout(() => {
mySubject.subscribe(val => console.log(`#2 ${val}`));
}, 5000);
A function which accepts a stream and returns a new observable
A function which accepts a stream and returns a new observable
corresponding to array methods
import { from } from 'rxjs';
import { map, filter } from 'rxjs/operators';
const numbers = [1, 2, 3, 4, 5];
const source$ = from(numbers);
const result$ = source$.pipe(
map(number => number * 10),
filter(number => number > 30)
);
result$.subscribe(console.log);
console output: 40, 50
A function which accepts a stream and returns a new observable
corresponding to array methods
encapsulating common logic
import { interval } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
const fastSource$ = interval(10);
const result$ = fastSource$.pipe(
throttleTime(2000)
);
result$.subscribe(console.log);
import { from } from 'rxjs';
import { map, filter } from 'rxjs/operators';
const numbers = [1, 2, 3, 4, 5];
const source$ = from(numbers);
const result$ = source$.pipe(
map(number => number * 10),
filter(number => number > 30)
);
result$.subscribe(console.log);
console output: 40, 50
import { from } from 'rxjs';
import { map, filter } from 'rxjs/operators';
const numbers = [1, 2, 3, 4, 5];
const source$ = from(numbers);
const result$ = source$.pipe(
map(number => number * 10),
filter(number => number > 30)
);
result$.subscribe(console.log);
console output: 40, 50
Exercises
https://stackblitz.com/edit/hg-workshop-11-2019-task-1
https://stackblitz.com/edit/hg-workshop-11-2019-task-2
https://stackblitz.com/edit/hg-workshop-11-2019-task-3
https://stackblitz.com/edit/hg-workshop-11-2019-task-4
Solutions
https://stackblitz.com/edit/hg-workshop-11-2019-task-1-solution
https://stackblitz.com/edit/hg-workshop-11-2019-task-2-solution
https://stackblitz.com/edit/hg-workshop-11-2019-task-3-solution
https://stackblitz.com/edit/hg-workshop-11-2019-task-4-solution
wojtrawi@gmail.com