- Intro.
- Approaches to deal with asynchronicity.
- Reactive Programming.
- Plumbing!
- Observables.
- Operators.
- Code examples.
- Final notes.
- A way to manage asynchronicity.
- This is NOT a talk about React.
- Based on the ReactiveX library.
- Usable in many languages in addition to JavaScript: PHP, Java, Scala, C#, C++, Pyhton and others.
- It greatly simplifies asynchronous working.
- Very easy to combine and manage asynchronous data sources.
- Generates a shorter, simpler and more intuitive code*.
- Maintainability.
- Unpredictable events over time.
- The browser environment is asynchronous.
- AJAX.
- User interaction (mouse, keyboard, etc).
- Timers or animations
- WebSockets.
- Workers.
var doc;
memStorage.get(docId, response => {
doc = memResponse;
if (!memResponse) {
localStorage.get(docId, localResponse => {
doc = localResponse;
if (!localResponse) {
serverStorage.get(docId, serverResponse => {
doc = serverResponse;
if (!serverResponse) {
// Error.
}
});
}
});
});
- Objects that wrap asynchronous operations and react when there is a result.
- They're almost callbacks turned into objects.
- They greatly improve flow and error management.
- Added to ES2015 (ECMAScript 6).
- They are resolved only once: they return a single value.
- Following the execution flow may not be trivial.
- They are not lazy.
- They are not cancelables.
- Promise hell.
- It brings functional programming capabilities to imperative programming.
- Programming using asynchronous data streams.
- Declaration of data pipes that process and transform the data that crosses them.
- Declaration of reactions to changes.
- Similar example: how Angular, React and Vue.js update rendering on data change.
- Is about creating data pipes.
- The pipe that certain data crosses.
- The pipe transforms the data
- When data reaches the end of the pipe a reaction is triggered.
Example: Click event listener.
jQuery('#grip').click(function() {
jQuery('#panel').slideUp();
});
Example: From a click to an AJAX request, and then to a instantiated object list.
- Observables from Observer pattern.
- Data streams.
- They emmit data until they finish or an error is triggered.
- Simple way to show data flow over time.
- Data flow that emits 4 elements and then finishes.
- Data flow that emits 3 elements and then emits an error.
- They allow to chain streams.
- They allow to transform the stream data.
- They allow to modulate streams.
- They can create streams.
- They can combine streams
Filter operator, filters values that don't match the condition.
Map operator, transforms stream data.
- Manual chronometre that accumulates time.
- A button to enable it.
- Another button to pause/continue.
var clockValue = 0;
var clockOn = true;
const btS$ = fromEvent(buttonStart, 'click');
const btP$ = fromEvent(buttonPause, 'click');
const clock$ = interval(1000);
btP$.subscribe(() => clockOn = !clockOn);
clock$.subscribe(x => output1.innerHTML = x);
clock$
.pipe(
combineLatest(btS$, v => v),
filter(() => clockOn))
.subscribe(() => output2.innerHTML = clockValue++);
clock$ ---1---2---3---4---5---6---7---8---9------>
do
---1---2---3---4---5---6---7---8---9------>
btS$ --------x--------------------------------->
combineLatest
--------2--3---4---5---6---7---8---9------>
filter (clockOn)
--------2--3---4---6-----------8---9------>
btP$ ---------------------x--------x----------->
clockV 000000001112222333344444444444455556666--->
clockOn 111111111111111111111000000000011111111--->
var button = document.querySelector('.this');
var clickStream = fromEvent(button, 'click');
var text = document.querySelector('h2');
var multiClickStream = clickStream.pipe(
buffer(interval(660)),
map(list => list.length),
filter(x => x >= 2));
multiClickStream.subscribe(numclicks => {
text.appendChild(createItem(1));
});
multiClickStream.pipe(delay(3000))
.subscribe(suggestion => {
text.removeChild(h2elem.firstChild)
});
fromEvent(button, 'click')
.pipe(
map(() => 'https://example.com/api/classification'),
flatMap(url => http.get(url)),
map(items => items.map(new MyItem(item))))
.subscribe(instances => this.list = instances);
Auto refresh
fromEvent(button, 'click')
.pipe(
merge(interval(60000)),
map(() => 'https://example.com/api/classification'),
flatMap(url => http.get(url)),
map(items => items.map(new MyItem(item))))
.subscribe(instances => this.list = instances);
Optional auto refresh
interval(60000)
.pipe(
filter(() => this.autorefresh),
merge(fromEvent(button, 'click')),
map(() => 'https://example.com/api/classification',
flatMap(url => http.get(url)),
map(items => items.map(new MyItem(item)))))
.subscribe(instances => this.list = instances);
Optional auto refresh and error management.
interval(60000)
.pipe(
filter(() => this.autorefresh),
merge(fromEvent(button, 'click')),
map(() => 'https://example.com/api/classification'),
flatMap(url => http.get(url)),
map(items => items.map(new MyItem(item))))
.catch(err => of(this.list))
.subscribe(instances => this.list = instances);
- You can express from simple reactions to extremely complex reactions to change.
- No more hells.
- Observables resolve as many times as needed.
- Execution flow is intuitive *.
- It's lazy.
- It's cancellable.
- With many ashynchonous data sources.
- Complex interactions.
- Complex interdependency.
- To avoid internal state to manage asynchronous events.
- They are not EventEmitter.
- Can be asyncronous or synchronous.
- Can be cold o hot.
- Can be multicast o unicast.
- Can share or not the data source with their subscriptors.
Because others have already done it.
- It can express very complex models.
- It handles any data source.
- Observables: proposed for standard, currently in stage 1.
- Less code, improved maintanibility.
- Available in many languages.
- Asynchronicity.
- The introduction to Reactive Programming you've been missing: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
- Interactive marble diagrams: http://rxmarbles.com/
- Rx Visualizer: https://rxviz.com/
- ReactiveX: http://reactivex.io/
- Ben Lesh: https://medium.com/@benlesh/