REACTIVE JAVASCRIPT MIT RXJS - BASTA! 2016
MAXIMILIAN BERGHOFF - 02.03.2016
Maximilian Berghoff
@ElectricMaxxx
github.com/electrimaxxx
Mayflower GmbH - Würzburg
Maximilian.Berghoff@mayflower.de
REACTIVE EXTENSIONS -
RX
HISTORY
ERIK MEIER
BRAIN BACKMAN
MATHEW PODWYSOCKI
LINQ TO EVENTS
VOLTA
WINDOWS FORMS
<=>
WEB FORMS
BEISPIEL:
DRAG & DROP
MAUSBEWEGUNG VERFOLGEN
EVENT LISTENER REGISTRIEREN
elem.addEventListener('mousedown', mousedown, false); 
elem.addEventListener('mouseup', mouseup, false); 
elem.addEventListener('mousemove', mousemove, false); 
MOUSE DOWN
function mousedown(e) { 
    isDown = true; 
    state = { startX: e.offsetX, startY: e.offsetY}; 
}
MOUSE MOVE
function mousemove(e) { 
    if (!isDown) {return;} 
    var delta = { 
        endX: e.clientX ­ state.startX, 
        endY: e.clientY ­ state.startY 
    };
}
MOUSE UP
function mouseup (e) { 
    isDown = false; 
    state = null; 
}
UNSUBSCRIBE
function dispose() { 
    elem.removeEventListener('mousedown', mousedown, false); 
    elem.removeEventListener('mouseup', mouseup, false); 
    elem.removeEventListener('mousemove', mousemove, false); 
}
DIE AKTEURE
ITERATOR PATTERN
var Iterator = function () {}; 
Iterator.prototype.next(); 
Iterator.prototype.rewind(); 
Iterator.prototype.current(); 
Iterator.prototype.hasNext(); 
TRAVERSIEREN
while (Iterator.hasNext()) { 
    console.log(Iterator.next()); 
}
GEDANKENSPIEL
Liste von Cocktails
Eigenschaften: id, name, zutaten, prozent, ...
Aufgabe: "id & name von allem Contails mit prozent > 5.0"
var cocktails = [ 
    {id: 100001, name: 'Piña Colada', zutaten: [], prozent: 5.0 }, 
    { id: 100002, name: ' Tequila Sunrise', zutaten: [], prozent: 6.0 },
    { id: 100003, name: ' Long Island', zutaten: [], prozent: 7.0 }, 
];
var newList = []; 
for(var i = 0; i <= cocktails.length; i++) { 
    if (cocktails[i].prozent > 5.0) { 
        newList.push({id: cocktails[i].id, title: cocktails[i].title}) 
    }
}
console.log(newList); 
var newList = []; 
cocktails.forEach(function (cocktail) { 
    if (cocktails[i].prozent > 5.0) { 
        newList.push({id: cocktail.id, title: cocktail.title}) 
    }
});
var godOnes = cocktails 
    .filter(function (cocktail) { 
      return cocktail.prozent > 5; 
  })
  .map(function (cocktail) { 
      return {id: cocktail.id, name: cocktail.name}; 
  });
OBSERVER PATTERN
Observable.prototype.subscribe() 
Observer.prototype.notify() 
var Observable = function () {}; 
Observable.prototype.subscribe = function () {}; 
Observable.prototype.unsubscribe = function () {}; 
var Observer = function () {}; 
Observer.prototype.notify = function() {}; 
WARUM?
Entkopplung
weniger prozedualer Code
Erweiterbarkeit erhöht
DIE HOCHZEIT
By Ziko van Dijk (shot by myself) [ or ],GFDL CC BY-SA 3.0 via Wikimedia
Commons
REACTIVE EXTENSION
RxJava
RxJS
Rx.Net
Rx.Scala
Rx.Clojure
Rx.Swift
...
REACTIVEX.IO
GITHUB.COM/REACTIVE-EXTIONSION
STREAM VON EVENTS
var list = [1, 2, 3, 4, 5]; 
list.forEach(function (item) { 
    console.log("nexItem: %s", item); 
});
var list = [1, 2, 3, 4, 5]; 
var source = Rx.Observable.fromArray(list); 
var disposal = source.subscribe( 
    function (x) {console.log('Next: ' + x);}, 
    function (err) {console.log('Error: ' + err);}, 
    function () {console.log('Completed');}); 
disposal.dispose(); 
OBSERVER
By Vince Alongi (Flickr) [ ],CC BY 2.0 via Wikimedia Commons
var disposal = source.subscribe( 
    function (x) {console.log('Next: ' + x);}, 
    function (err) {console.log('Error: ' + err);}, 
    function () {console.log('Completed');} 
);
function Observer() { } 
Observer.prototype.onNext = function (value) { ... }; 
Observer.prototype.onError = function (error) { ... }; 
Observer.prototype.onCompleted = function () { ... }; 
var source = Rx.Observable.range(1,10); 
var reducedSource = source.filter(function (value) { 
    return value % 2 === 0; 
});
var disposal1 = reducedSource.subscribe( 
    function (x) {console.log('Next 1: ' + x);}, 
    function (err) {console.log('Error 1: ' + err);}, 
    function () {console.log('Completed 1.');} 
);
disposal1.dispose(); 
var disposal2 = source.subscribe( 
    function (x) {console.log('Next 2: ' + x);}, 
    function (err) {console.log('Error 2: ' + err);}, 
    function () {console.log('Completed 2');} 
);
disposal2.dispose(); 
> Next 1: 2 
> Next 1: 4 
> Next 1: 6 
> Next 1: 8 
> Next 1: 10 
> Completed 1. 
> Next 2: 1 
> Next 2: 2 
> Next 2: 3 
> Next 2: 4 
> Next 2: 5 
> Next 2: 6 
> Next 2: 7 
> Next 2: 8 
> Next 2: 9 
> Next 2: 10 
> Completed 2 
OBSERVALBE
function Disposable() { } 
Disposable.prototype.dispose = function () { ... } 
function Observable() { } 
/**
 * @return Disposable 
 */
Observable.prototype.subscribe = function (observer) { ... } 
YOUTUBE
(ER-) ZEUGUNG
Rx.Observable.create() 
var source = Rx.Observable.create(function (observer) { 
  observer.onNext(42); 
  observer.onCompleted(); 
  return function () { 
    console.log('disposed'); 
  }
});
var subscription = source.subscribe( 
  function (x) { console.log('onNext: %s', x); }, 
  function (e) { console.log('onError: %s', e); }, 
  function () { console.log('onCompleted'); } 
  );
subscription.dispose(); 
> onNext: 42 
> onCompleted 
> disposed 
Rx.Observable.range() 
var source = Rx.Observable.range(1, 5); 
var subscription = source.subscribe( 
  function (x) { console.log('onNext: %s', x); }, 
  function (e) { console.log('onError: %s', e); }, 
  function () { console.log('onCompleted'); } 
);
> onNext: 1 
> onNext: 2 
> onNext: 3 
> onNext: 4 
> onNext: 5 
Rx.Observable.fromEvent(element, eventName, [selector]) 
// oder
Rx.Observable.fromCallback(func, [context], [selector]) 
var input = $('#input'); 
var source = Rx.Observable.fromEvent(input, 'keyup'); 
var subscription = source.subscribe( 
  function (x) {console.log('Next: key pressed!');}, 
  function (err) {console.log('Error: %s', err);}, 
  function () {console.log('Completed');}); 
var fs = require('fs'), 
    Rx = require('rx'); 
var exists = Rx.Observable.fromCallback(fs.exists); 
var source = exists('file.txt'); 
var subscription = source.subscribe( 
    function (x) {console.log('Next: ' + x);}, 
    function (err) {console.log('Error: ' + err);}, 
    function () {console.log('Completed');} 
  );
LINQ
LANGUAGE INTEGRATED QUERY
von Unbekannt [Public domain], via Wikimedia Commons
KOMBINATION
.concat(); 
// oder
.merge(); 
var sourceOne = Rx.Observable.range(1,5); 
var sourceTwo = Rx.Observable.range(6,5); 
var merged = sourceOne.concat(sourceTwo); 
var disposal = merged.subscribe(function (x) { 
    console.log('Concat onNext: ' + x);  
});
OUTPUT
> Concat onNext: 1 
> Concat onNext: 2 
> Concat onNext: 3 
> Concat onNext: 4 
> Concat onNext: 5 
> Concat onNext: 6 
> Concat onNext: 7 
> Concat onNext: 8 
> Concat onNext: 9 
> Concat onNext: 10 
var sourceOne = Rx.Observable.range(1,5); 
var sourceTwo = Rx.Observable.range(6,5); 
var merged = sourceOne.merge(sourceTwo); 
var disposal = merged.subscribe(function (x) { 
    console.log('Merged onNext: ' + x);  
});
OUTPUT
> Merged onNext: 1 
> Merged onNext: 6 
> Merged onNext: 2 
> Merged onNext: 7 
> Merged onNext: 3 
> Merged onNext: 8 
> Merged onNext: 4 
> Merged onNext: 9 
> Merged onNext: 5 
> Merged onNext: 10 
FILTER
var source = Rx.Observable.range(1,10); 
var filtered = source.filter(function (x) { 
    return x % 2 === 0; 
});
var disposal = filtered.subscribe(function (x) { 
    console.log('onNext: ' + x); 
});
OUTPUT
> onNext: 2 
> onNext: 4 
> onNext: 6 
> onNext: 8 
> onNext: 10 
PROJEKTIONEN
var list = [ 
    {id: 100001, name: 'Piña Colada', zutaten: [], prozent: 5.0 }, 
    { id: 100002, name: ' Tequila Sunrise', zutaten: [], prozent: 6.0 },
    { id: 100003, name: ' Long Island', zutaten: [], prozent: 7.0 }, 
];
var source = Rx.Observable.from(list); 
var ids = source.map(function (item) { 
    return item.id; 
});
var disposal = ids.subscribe(function (x) { 
    console.log('onNext Id: ' + x); 
});
disposal.dispose(); 
OUTPUT
onNext Id: 100001 
onNext Id: 100002 
onNext Id: 100003 
?
.flatMap(); 
var source = Rx.Observable 
    .range(1, 2) 
    .flatMap(function (x) { 
        return Rx.Observable.range(x, 2); 
    });
var subscription = source.subscribe( 
    function (x) { 
        console.log('onNext: ' + x); 
    }
);
return Rx.Observable.range(1, 2); 
return Rx.Observable.range(2, 2); 
OUTPUT
> onNext: 1 
> onNext: 2 
> onNext: 2 
> onNext: 3 
NOCH MEHR?
GITHUB/DOKUMENTATION
PROMISES?
Single Value
Cancellation?
ARRAY OPERATOREN
VS.
RX OPERATOREN
ARRAY OPERATOREN
Komplette Liste wird durch gereicht
dabei auf jedem Eintrag
Projektion - map, ..
Gefiltert - reduce, filter
Ergänzt - concat, merge
RX OPERTOREN
Jedes Event/Jeder Eintrag einzeln
dabei
Projektion - map, ..
Gefiltert - reduce, filter
Ergänzt - concat, merge
Filter = STOP => nicht weiter gereicht
Ergänzung nur der Zugang für weiteren Stream
ACTION
von Thiemo Schuff (Eigenes Werk) [ ],CC BY-SA 3.0 via Wikimedia
Commons
<input type="text" id="input"/> 
<h2>Results</h2> 
<ul id="results"> 
</ul>
    var $input = $('#input'); 
    var $results = $('#results'); 
    var suggestions = Rx.Observable.fromEvent($input, 'keyup'); 
var suggestions = Rx.Observable.fromEvent($input, 'keyup') 
        .pluck('target', 'value') 
        .filter(function(text) { return text.length > 2 }) 
        .debounce(500 /* ms */) 
        .distinctUntilChanged(); 
    ...
    flatMapLatest(function (term) { 
            return $.ajax({ 
                url: 'https://en.wikipedia.org/w/api.php', 
                dataType: 'jsonp', 
                data: { 
                    action: 'opensearch', 
                    format: 'json', 
                    search: term 
                } 
            }).promise(); 
        }); 
    ...
    .subscribe( 
        function(data) { 
            $results 
                .empty() 
                .append($.map(data[1], function (value) { 
                    return $('<li>').text(value); 
                })) 
        }, 
        function(error) { 
            $results 
                .empty() 
                .append($('<li>')) 
                .text('Error:' + error); 
        } 
    );
JS FIDDLE
By Musik- och teatermuseet (Own work) [ ],CC BY-SA 3.0 via Wikimedia
Commons
QUESTIONS?
Ask Now!
Twitter: @ElectricMaxxx
Mail: Maximilian.Berghoff@mayflower.de
LINKS
, Slideshare folgtSlides in Markdown
RxJS docs
Marbles
Liste an Tutorials
Repository
Ausführliches Tutorial
Video Tutorials
Buch
ALTERNATIVEN
cyclejs
BACONJS
THANK YOU!
< <

Reactive java script mit rxjs basta! 2016