RxJS
wprowadzenie do programowania reaktywnego
Rodzaje asynchroniczności w aplikacja webowych
- AJAX
- DOM Events
- animacje
- WebSocket data
- WebWorkers results
- setInterval
Przykład
getData(query, (data) => {
console.log('data received', data);
});
Problemy z asynchronicznością
getData(query, (data1) => {
console.log('data1 received', data1);
getData(data1.id, (data2) => {
console.log('data2 received', data2);
getData(data2.url, (data3) => {
console.log('data3 received', data3);
getData(data3.name, (finalData) => {
console.log('finalData received', finalData);
finalStuff = doStuff(finalData);
});
});
});
});
callback hell
aka "flying V"
Rozwiązanie - Promises
let finalStuff = getData(query)
.then(data1 => {
console.log('data1 received', data1);
return getData(data1.id);
})
.then(data2 => {
console.log('data2 received', data2);
return getData(data2.url);
})
.then(data3 => {
console.log('data3 received', data3);
return getData(data3.name);
})
.then(finalData => {
console.log('finalData received', finalData);
return doStuff(finalData);
})
Rozwiązanie - Promises
Pros
- synchroniczna reprezentacja asynchroniczności
- immutable
reprezentacja wartości z przyszłości

Promises
let finalStuff = getData(query)
.then(getOtherData)
.then(getAnotherOne)
.then(doFinallStuff)
Rozwiązanie - Promises
Pros
- synchroniczna reprezentacja asynchroniczności
- immutable
Cons
- tylko AJAX jest pojedynczą wartością
reprezentacja wartości z przyszłości

Rodzaje asynchroniczności w aplikacja webowych
- AJAX
- DOM Events
- animacje
- WebSocket data
- WebWorkers results
- setInterval
Rozwiązanie - Promises
Pros
- synchroniczna reprezentacja asynchroniczności
- immutable
Cons
- tylko AJAX jest pojedynczą wartością
- nie można anulować (a AJAXa można)
reprezentacja wartości z przyszłości

Observable

Observable
Synchronous | Asynchronous | |
---|---|---|
single value | Object | Promise |
multiple values | Iterables (Array / Set / Map) |
Observable |
Observable
- strumienie / zbiory
- zdarzenia jak kolekcje
- immutable
- lazy
- można anulować (przykład)
dowolna ilość obiektów na przestrzeni dowolnego czasu
Observable
strumień

Observable
operator

Observable
operatory
audit, auditTime, buffer, bufferCount, bufferTime, bufferToggle, bufferWhen,
cache, catch, combineAll, combineLatest, concat, concatAll, concatMap,
concatMapTo, count, debounce, debounceTime, defaultIfEmpty, delay, delayWhen,
dematerialize, distinct, distinctKey, distinctUntilChanged,
distinctUntilKeyChanged, do, elementAt, every, exhaust, exhaustMap, expand,
filter, finally, find, findIndex, first, groupBy, ignoreElements, isEmpty, last,
let, map, mapTo, materialize, max, merge, mergeAll, mergeMap, mergeMapTo, mergeScan,
min, multicast, observeOn, onErrorResumeNext, pairwise, partition, pluck, publish,
publishBehavior, publishLast, publishReplay, race, reduce, repeat, repeatWhen, retry,
retryWhen, sample, sampleTime, scan, sequenceEqual, share, single, skip, skipUntil,
skipWhile, startWith, subscribeOn, switch, switchMap, switchMapTo, take, takeLast,
takeUntil, takeWhile, throttle, throttleTime, timeInterval, timeout, timeoutWith,
timestamp, toArray, toPromise, window, windowCount, windowTime, windowToggle,
windowWhen, withLatestFrom, zip, zipAll
Observable
zdarzenia jak kolekcje
let iterable = [0, 1, 1, 2, 3, 5, 8, 13];
iterable
.filter(x => x % 2 === 0)
.map(x => x + x)
.forEach(x => console.log("x: ", x));
observable
.filter(x => x % 2 === 0)
.map(x => x + x)
.forEach(x => console.log("x: ", x));
RxJS - LoDash for async
Observable
tworzenie observable
var source = Rx.Observable.create(function (observer) {
observer.onNext(42);
observer.onCompleted();
// Note that this is optional, you do not have to return this if you require no cleanup
return function () { console.log('disposed'); };
});
var source = Rx.Observable.generateWithRelativeTime(
1,
x => x < 100,
x => x + 1,
x => x,
x => 100 * x
).timeInterval();
var subscription = source.subscribe(
x => console.log('Next: ', x),
x => console.log('Error: ', x),
x => console.log('Completed')
);
Observable
tworzenie observable
let fromArray = Rx.Observable.from([1, 2, 3, 4, 5, 6]);
let map = new Map([[1, 2], [2, 4], [4, 8]]);
let fromMap = Rx.Observable.from(m);
let fromStr = Rx.Observable.from("abcdefgh");
let fromInterval = Rx.Observable.interval(500).timeInterval().take(3);
let justTwo = Rx.Observable.just(2);
let zeroToThree = Rx.Observable.range(0, 3);
let threeTimes = Rx.Observable.repeat(42, 3);
let empty = Rx.Observable.empty();
let never = Rx.Observable.never();
let throw = Rx.Observable.throw();
Observable
tworzenie observable
let inputKeydowns = Rx.Observable.fromEvent(input, 'keydown');
let fromPromise = Rx.Observable.startAsync(function () {
return RSVP.Promise.resolve(42);
});
let fromAJAX = Rx.DOM.ajax({
method: 'GET',
url: 'domain.com/url',
responseType: 'json'
});
function initialize() {}
let ready = Rx.DOM.ready().subscribe(initialize);
let socket = Rx.DOM.fromWebSocket(
'ws://echo.websocket.org',
null, // no protocol
openObserver,
closingObserver);
Observable
bindings
- DOM binding,
- AJAX,
- jQuery,
- nodeJS,
- Angular HTTP/Realtime Data services,
- React Stores,
- Ember computed property,
- etc, etc,
Observable
anulowanie zapytań - autocomplete
// search input
var q = document.querySelector('#q');
// serch suggestions container
var resultList = document.querySelector('#results');
// stream of keyups on the input
var keyups = Rx.Observable.fromEvent(q, 'keyup');
keyups
// Throttle events to at most one on 0,5s
.throttle(500)
// transform to stream of values
.map(() => q.value)
// side effect - show the spinner next to input
.do(() => q.classList.add('spinner'))
// transform every query to Ajax stream an map every for one stream with latest emit item
.flatMapLatest(query => Rx.DOM.ajax({
method: 'GET',
url: '/autocomplete?q=' + query,
responseType: 'json'
}))
// async is over - hide the spinner
.do(() => q.classList.remove('spinner'))
// get results from each response
.map(r => r.response)
// decorate results with html and join to one
.map(results => results.reduce((html, result) => `${html}<li>${result}</li>`, ''))
// success - insert result to the DOM
.subscribe(resultsHTML => resultList.innerHTML = resultsHTML,
// fail
err => console.error(err));
Observable
łączenie strumieni - drag'n'drop
const { fromEvent } = Rx.Observable;
const target = document.querySelector('.box');
const mousedown = fromEvent(target, 'mousedown'); // ---o-------------------------------------->
const mouseup = fromEvent(target, 'mouseup'); // -----------------------------o------------>
const mousemove = fromEvent(document, 'mousemove'); // -ooooo----ooo----oo---o--o-------ooo---o-->
// mouse drag event stream is every mouse move during mousedown until mouseup happen
const mousedrag = mousedown.flatMap((md) => {
const startX = md.clientX + window.scrollX,
startY = md.clientY + window.scrollY,
startLeft = parseInt(md.target.style.left, 10) || 0,
startTop = parseInt(md.target.style.top, 10) || 0;
return mousemove.map((mm) => { // ---(1,2)-(1,3)-(2,6) --->
mm.preventDefault();
return {
left: startLeft + mm.clientX - startX,
top: startTop + mm.clientY - startY
};
}).takeUntil(mouseup); // ----oo----ooo----oo---o--o---------------->
});
Reactive Extensions

- RxJS v.4.1 - stable
- RxJS v.5.0.0-beta.12
- wsparcie od IE10 (IE9?)
- w całości przepisane w ES6
- większa modularność (modułowość?)
- poprawiona wydajność (~4.6x)
github.com/Reactive-Extensions/RxJS
github.com/ReactiveX/rxjs
Reactive Extensions







RxLua, Rx.rb, RxPy,
RxGroovy, RxJRuby, RxPHP
Dziękuję
Rx Dokumentacja - z przykładami dla każdego języka
http://reactivex.io/intro.html
RxDOM - binding do drzewa DOM
https://github.com/Reactive-Extensions/RxJS-DOM
Ben Lesh - RxJS Version 5
http://bit.ly/BenLeshRxJS5
Jafar Husain - ES7: The Evolution of JavaScript
http://bit.ly/es2016evo
Jafar Husain - Async JavaScript with Reactive Extensions
http://bit.ly/asyncWithRx
RX JS Angular 2.0
By Tarun Sharma
RX JS Angular 2.0
- 1,029