getData(query, (data) => {
console.log('data received', data);
});
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"
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);
})
Pros
reprezentacja wartości z przyszłości
let finalStuff = getData(query)
.then(getOtherData)
.then(getAnotherOne)
.then(doFinallStuff)
Pros
Cons
reprezentacja wartości z przyszłości
Pros
Cons
reprezentacja wartości z przyszłości
Synchronous | Asynchronous | |
---|---|---|
single value | Object | Promise |
multiple values | Iterables (Array / Set / Map) |
Observable |
dowolna ilość obiektów na przestrzeni dowolnego czasu
strumień
operator
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
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
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')
);
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();
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);
bindings
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));
łą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---------------->
});
github.com/Reactive-Extensions/RxJS
github.com/ReactiveX/rxjs
RxLua, Rx.rb, RxPy,
RxGroovy, RxJRuby, RxPHP
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