Part 1 - Reactive programming and RxJS
Part 2 - Observables in Angular
// concert spectators
let inMainStand = 300;
let inVipStand = 50;
// code...
let total = inMainStand + inVipStand; // 350
// code...
inMainStand += 60;
console.log(total); // total = ?
total = inMainStand + inVipStand; // 410
Product
Vendor
Cart
Cupon
Sale
Payment
User profile
Invoice
Cart
Invoice
Add product...
...update the total
Cart
Invoice
import {Invoice} from './invoice';
class Cart {
constructor(invoice: Invoice){ ... }
addProduct(product) {
...
this.invoice.update(product); // needs to be public
...
}
}
Passive
Proactive
Cart
Invoice
import {Cart} from './cart';
class Invoice {
constructor(cart: Cart){ ... }
init() {
...
this.cart.onCartChange( callback )
}
}
Reactive
Listenable
Cart
Cupon
Sale
Payment
Invoice
Passive programming
Cart
Cupon
Sale
Payment
Invoice
Reactive programming
Interruptions in web applications
(Global) Event Bus
Observer pattern
Image credits:
https://www.dofactory.com/javascript/observer-design-pattern
Observer vs PubSub
Managing side-effects
SYNC
ASYNC
SINGLE
MULTIPLE
function
Managing side-effects
SYNC
ASYNC
SINGLE
MULTIPLE
function
generators
Managing side-effects
SYNC
ASYNC
SINGLE
MULTIPLE
function
promises
generators
Managing side-effects
SYNC
ASYNC
SINGLE
MULTIPLE
function
promises
generators
observables
Michael Hladky
@Michael_Hladky
- marble diagrams
- inspirational talks
Ben Lesh
@BenLesh
inspirational talks -
work on RxJS -
Dealing with async in our apps:
getData(function(successResult) {
// do something with the data
});
getData(
function(successResult) {
// do something with the data
},
function(faliureError) {
// handle the error
},
);
let result = fetch('api/users.json');
result
.then(success => {
// handle success
})
.catch(error => {
// handle error
})
result
.then(...)
.then(...)
.then(...)
Unifying callbacks, promises and event handlers
Shape of an observable:
let observable$ = new Observable(() => {
})
Observable
excersise file: https://stackblitz.com/edit/adv-rxjs-1
let observable$ = new Observable(observer => {
observer.next(1);
observer.next(2);
})
Observer
let observable$ = new Observable(observer => {
observer.next(1);
observer.next(2);
})
observable$.subscribe(value => {
console.log(value)
}
Subscription
let observable$ = new Observable(observer => {
observer.next(1);
observer.next(2);
return () => {
// cleanup resources when done
};
})
const subscription = observable$.subscribe(value => {
console.log(value)
})
subscription.unsubscribe(); // stop emitting values
let observable$ = new Observable(observer => {
observer.next(1);
observer.next(2);
observer.error(new Error('Bad'));
})
const subscription = observable$.subscribe(
value => { console.log(value)},
error => { console.log(error.message)}
)
Creation functions
of(value1, value2, value3)
from(promise/itterable/observable)
fromEvent(target, eventName)
interval(time)
timer(time)
let promise = new Promise((resolve, reject) => {
doAsyncThing((err, value) => {
if (err) {
reject(err);
} else {
resolve(value)
}
})
})
promise.then(successFn, errorFn);
let promise = new Promise((resolve, reject) => {
doAsyncThing((err, value) => {
if (err) {
reject(err);
} else {
resolve(value)
}
})
})
promise.then(successFn, errorFn);
// COLD
var cold = new Observable((observer) => {
var producer = new Producer();
// have observer listen to producer here
});
// HOT
var producer = new Producer();
var cold = new Observable((observer) => {
// have observer listen to producer here
});
Observables are unicast - each subscriber manages its own execution context
Subjects are multicast observables - values are multicasted to many Observers
Types of subjects
Observables are collections of pushed values or events that we can:
let array = [1,2,3,4,5];
array
.map(v => v * v)
.filter(v => v > 5 && v < 20)
.reduce((acc, curr) => acc + curr, 0)
// 25
let observable$ = from([1,2,3,4,5]);
observable$
.pipe(
map(v => v * v),
filter(v => v > 5 && v < 20),
reduce((acc, curr) => acc + curr, 0)
)
.subscribe(val => console.log(val))
// 25
excersise file: https://stackblitz.com/edit/adv-rxjs-2
const toUpperCase =
(source: Observable<any>) => {
return new Observable((observer) => {
return source.subscribe({
next(x) {
observer.next( x.toUpperCase() )
}
})
}
)}
from('hello')
.pipe(toUpperCase)
.subscribe(val => l(val))
excersise file: https://stackblitz.com/edit/adv-rxjs-3
const pow = (p = 1) =>
(source: Observable<any>) => {
return new Observable((observer) => {
return source.subscribe({
next(val) {
observer.next( Math.pow(val, p) )
}
})
}
)}
from([1, 2, 3])
.pipe(pow(3))
.subscribe(val => l(val))
Operators can take parameters as well
const buttonObs$ = fromEvent(querySelector('button'), 'click');
buttonObs$.subscribe(() => {
http$.get('/api/users').subscribe( data => {
// handle loaded data
})
})
excersise file: https://stackblitz.com/edit/rxjs-adv-4
const obs$ = new Observable(observer => {
observer.closed; // false
observer.next(1); // emit 1
observer.complete();
observer.closed; // true
observer.next(2); // won't emit
});
excersise file: https://stackblitz.com/edit/rxjs-adv-5
const obs$ = new Observable(observer => {
observer.closed; // false
observer.next(1); // emit 1
observer.error(new Error('Bad!'));
observer.closed; // true
observer.next(2); // won't emit
});
obs$
.subscribe({
next: v => console.log(v),
error: e => console.log(e.message)
});
const obs$ = new Observable(observer => {
observer.next(1);
observer.error(new Error('BANG!'));
}).pipe(
catchError(err => {
console.log('Intercepted error:' + err);
return of('I got this');
})
)
obs$.subscribe(v => console.log(v));
// 1 'I got this'
const getData$ = http.get('/api/users')
.pipe(
retry(3),
catchError(() => of('Something went wrong');
)
getData$.subscribe(value => console.log(value));
Schedulers control timing around when an event occurs
RxJS Schedulers
excersise file: https://stackblitz.com/edit/rxjs-adv-6
Angular power-up -> async pipe