Observables and RxJS
What is Observable?
Opposite for Iterator)
function* iterator(){
let index = 0;
while(true)
yield index++;
}
for (let i of iterator()) {
if (i < 10) {
console.log(i);
} else {
break;
}
}
console.log("finished");
(async function () {
function* iterator(){
let index = 0;
while(true) {
yield new Promise((r) => {
setTimeout(() => { r(index++) }, 1000)
});
}
}
for await (let i of iterator()) {
if (i < 10) {
console.log(i);
} else {
break;
}
}
console.log("finished");
})();
Observer
getData().subscribe((data) => {
render(data);
});
Why we need Observable?
We have Promises and Thunks
function httpGet(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (this.status == 200) {
resolve(this.response);
} else {
var error = new Error(this.statusText);
error.code = this.status;
reject(error);
}
};
xhr.onerror = function() {
reject(new Error("Network Error"));
};
xhr.send();
});
}
Promise.race([
new Promise((r) => {
setTimeout(() => { r("hello") }, 2000);
}),
new Promise((_, r) => {
setTimeout(() => { r(new Error("Timeout")) }, 1000)
})
])
.then(a => console.log(a), a => console.warn(a))
We have EventEmitter
var events = require('events');
var eventEmitter = new events.EventEmitter();
var listner1 = () => console.log('listner1 executed.');
var listner2 = () => console.log('listner2 executed.');
eventEmitter.addListener('connection', listner1);
eventEmitter.on('connection', listner2);
var eventListeners = events.EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");
eventEmitter.emit('connection');
eventEmitter.removeListener('connection', listner1);
eventEmitter.emit('connection');
console.log("Program Ended.");
Why we need Observables?
Observables
- Common protocol
- Lazy computations
- Flow Control
Common protocol
Promise
function Producer () {
return new Promise (r => {
let data = 24;
setTimeout(() => {
r({
data,
next: new Promise((r2) => {
setTimeout(() => {
r2({ data: 18, next: undefined });
}, 1000);
})
});
}, 1000);
});
}
var result = 0;
Producer().then(function Consumer ({ data, next }) {
// do something with data;
result += data;
if (next) {
return next.then(Consumer);
}
return `finished: ${ result }`;
}).then(a => console.log(a));
EventEmitter
var events = require("events");
function Producer () {
let target = new events.EventEmmiter();
let data = 24;
setTimeout(() => {
target.emit("progress", data);
setTimeout(() => {
target.emit("progress", 18);
target.emit("end", undefined);
}, 1000);
}, 1000);
// target.emit("error", new Error("some error that should stop all processes"));
return target;
}
Observable
new Observable(observer => {
let handler = event => observer.next(event);
element.addEventListener("mousemove", handler, true);
setTimeout(() => {
observer.complete();
}, 1000);
// observer.error("some error");
return () => {
element.removeEventListener(eventName, handler, true);
};
});
let subscription = observable.subscribe({
next(val) { console.log("Received key command: " + val) },
error(err) { console.log("Received an error: " + err) },
complete() { console.log("Stream complete") },
});
interface Subscription {
// Cancels the subscription
unsubscribe() : void;
// A boolean value indicating whether the subscription is closed
get closed() : Boolean;
}
Lazy computations
function SomeCrazyComputations () {
return new Promise(() => {
// really heavy stuff
});
}
var result = SomeCrazyComputations().then((data) => {
// crazy tranformations
return data;
});
setTimeout(() => {
result.then(render);
}, 1000);
function SomeCrazyComputations () {
return new Promise(() => {
// really heavy stuff
});
}
let computations = [
(data) => data.map( ... ),
(data) => data.filter( ... ),
(data) => data.reduce( ... )
];
setTimeout(() => {
[ ...computations, render ].reduce((p, f) => p.then(f), Promise.resolve());
}, 1000);
Generators
EventEmmiter
var events = require("events");
var bus = new events.EventEmitter();
function SomeCrazyComputations (target) {
target.on("start", () => {
setTimeout(() => {
// really heavy stuff
target.emit("progress", date);
}, 1000);
});
}
SomeCrazyComputations(bus);
function SomeCrazyTransformations (target) {
target.on("progress", (data) => {
// crazy tranformations
target.emit("progress-2", data);
});
});
SomeCrazyTransformations(bus);
setTimeout(() => {
bus.on("progress-2", render);
bus.emit("start", undefined);
}, 1000);
Observables
function listen(element, eventName) {
return new Observable(observer => {
// Create an event handler which sends data to the sink
let handler = event => observer.next(event);
// Attach the event handler
element.addEventListener(eventName, handler, true);
// Return a cleanup function which will cancel the event stream
return () => {
// Detach the event handler from the element
element.removeEventListener(eventName, handler, true);
};
});
}
// Return an observable of special key down commands
function commandKeys(element) {
let keyCommands = { "38": "up", "40": "down" };
return listen(element, "keydown")
.filter(event => event.keyCode in keyCommands)
.map(event => keyCommands[event.keyCode])
}
let subscription = commandKeys(inputElement);
let subscription = commandKeys(inputElement).subscribe({
next(val) { console.log("Received key command: " + val) },
error(err) { console.log("Received an error: " + err) },
complete() { console.log("Stream complete") },
});
Hot and Cold Observables
Flow control
How to cancel a Promise?
async function (coords) {
let countries = await getCountries(coords);
render(countries);
let hotels = await getHotelsByCountries(countries);
render(hotels);
let facilities = await getFacilitiesByHotels(hotels);
render(facilities);
let images = await getImages(facilities);
render(images);
}
async function (coords, promise) {
let countries = await Promise.race([getCountries(coords), promise]);
render(countries);
let hotels = await Promise.race([getHotelsByCountries(countries), promise]);
render(hotels);
let facilities = await Promise.race([getFacilitiesByHotels(hotels), promise]);
render(facilities);
let images = await Promise.race([getImages(facilities), promise]);
render(images);
}
EventEmmiter
Try to cancel this code
var events = require("events");
var bus = new events.EventEmitter();
function SomeCrazyComputations (target) {
target.on("start", () => {
setTimeout(() => {
// really heavy stuff
target.emit("progress", date);
}, 1000);
});
}
SomeCrazyComputations(bus);
function SomeCrazyTransformations (target) {
target.on("progress", (data) => {
// crazy tranformations
target.emit("progress-2", data);
});
});
SomeCrazyTransformations(bus);
setTimeout(() => {
bus.on("progress-2", render);
bus.emit("start", undefined);
}, 1000);
var events = require("events");
var bus = new events.EventEmitter();
function SomeCrazyComputations (target) {
target.on("start", () => {
setTimeout(() => {
// really heavy stuff
target.emit("progress", date);
}, 1000);
});
target.on("abort", () => { ... });
}
SomeCrazyComputations(bus);
function SomeCrazyTransformations (target) {
target.on("progress", (data) => {
// crazy tranformations
target.emit("progress-2", data);
});
target.on("abort", () => { ... });
});
SomeCrazyTransformations(bus);
setTimeout(() => {
bus.on("progress-2", render);
bus.emit("start", undefined);
}, 1000);
Observables
subscription.unsubscribe();
let data = Observable
.fromPromise(getCountries())
.flatMap(c => Observable.fromPromise(getHotels(c)))
.flatMap(h => Observable.fromPromise(getFacilities(h)))
.flatMap(f => Observable.fromPromise(getImages(f)));
setTimeout(() => {
data.subscribe( ... );
}, 1000);
setTimeout(() => {
data.unsubscribe();
}, 3000);
One small example
How much time do you need for Drag and drop
You are a great programmer)
How much lines of code so you need?
let getEltDrags = elt =>
Observable.fromEvent(elt, "mousedown")
.map(() => Observable.fromEvent(docucment, "mousemove")
takeUntil(Observable.fromEvent(docucment, "mouseup")))
.concatAll();
getEltDrags(img).forEach(ev => {
img.style.left = ev.pageX;
img.style.top = ev.pageY;
});
Promise vs Observable
EventEmitter vs Observable
Observer
By Vladimir
Observer
- 228