rxjs evolved

49

Click here to load reader

Upload: trxcllnt

Post on 13-Jan-2017

1.945 views

Category:

Software


0 download

TRANSCRIPT

Page 1: RxJS Evolved

RXJS EVOLVED

Page 2: RxJS Evolved

PAUL TAYLOR@trxcllnt

UI PLATFORM TEAM @

Page 3: RxJS Evolved

OBSERVABLE

Page 4: RxJS Evolved

EVENTEMITTER..... OBSERVABLE ≠ EVENTDISPATCHER

EVENTDELEGATE...

Page 5: RxJS Evolved

“The idea of future values — maybe.”

–ME

Page 6: RxJS Evolved

SINGLE MULTIPLE

SYNCHRONOUS Function Enumerable

ASYNCHRONOUS Promise Observable

THE OTHER “IDEAS” OF VALUES

Page 7: RxJS Evolved

SINGLE MULTIPLE

PULL Function Enumerable

PUSH Promise Observable

THE OTHER “IDEAS” OF VALUES

Page 8: RxJS Evolved

FUNCTIONS// The “idea” of a random number

var getRandomNumber = function() {

return Math.random();

}

// A random number

var rand = getRandomNumber.call();

(LAZINESS)

Page 9: RxJS Evolved

ANATOMY OF OBSERVABLECREATION

SUBSCRIPTION DISPOSAL

Page 10: RxJS Evolved

var randomNumbers = Observable.create((s) => {

var i = setTimeout(() => {

s.next(Math.random());

s.complete();

}, 1000);

return () => clearTimeout(i);

});

var sub = randomNumbers.subscribe({

next(x) { console.log(x); },

error(e) { console.error(e); },

complete() { console.log(“done”); }

});

var randomNumbers = Observable.create((s) => {

var i = setTimeout(() => {

s.next(Math.random());

s.complete();

}, 1000);

return () => clearTimeout(i);

});

var randomNumbers = Observable.create((s) => {

var i = setTimeout(() => {

s.next(Math.random());

s.complete();

}, 1000);

ANATOMY OF OBSERVABLE★ CREATION

★ SUBSCRIPTION

★ DISPOSAL

var randomNumbers = Observable.create(

Page 11: RxJS Evolved

WHAT HAPPENS WHEN…var randomNumbers = Observable.create((s) => {

var i = setTimeout(() => {

s.next(Math.random());

s.complete();

}, 1000);

return () => clearTimeout(i);

});

randomNumbers.subscribe(x => console.log(‘1: ’ + x));

randomNumbers.subscribe(x => console.log(‘2: ’ + x));

Page 12: RxJS Evolved

>

> 1: 0.1231982301923192831231

> 2: 0.8178491823912837129834

>

THIS HAPPENS

Page 13: RxJS Evolved

EVENTEMITTER..... OBSERVABLE ≠ EVENTDISPATCHER

EVENTDELEGATE...

OBSERVABLE = FUNCTION...........

Page 14: RxJS Evolved

“Observable is a function that, when invoked, returns 0-∞ values between now and the end of time.”

–ME

Page 15: RxJS Evolved

OPERATORS

Page 16: RxJS Evolved

OPERATORSMETHODS THAT PERFORM

CALCULATIONS ON THE VALUES

MAP, FILTER, SCAN, REDUCE, FLATMAP, ZIP, COMBINELATEST, TAKE, SKIP, TIMEINTERVAL, DELAY, DEBOUNCE, SAMPLE, THROTTLE, ETC.

Page 17: RxJS Evolved

“lodash for events”–NOT ME

Page 18: RxJS Evolved

WRITING AN OPERATOR (OLD)class Observable {

constructor(subscribe) { this.subscribe = subscribe; }

map(selector) {

var source = this;

return new Observable((destination) => {

return source.subscribe({

next(x) { destination.next(selector(x)) },

error(e) { destination.error(e); },

complete() { destination.complete(); }

});

});

}

}

Page 19: RxJS Evolved

USING OPERATORSvar grades = { “a”: 100, “b+”: 89, “c-“: 70 };

Observable.of(“a”, “b+”, “c-”)

.map((grade) => grades[grade])

.filter((score) => score > grades[“b+”])

.count()

.subscribe((scoreCount) => {

console.log(scoreCount + “ students received A’s”);

});

Page 20: RxJS Evolved

SCHEDULERS

Page 21: RxJS Evolved

SCHEDULERSCENTRALIZED DISPATCHERS TO

CONTROL CONCURRENCY

IMMEDIATE TIMEOUT

REQUESTANIMATIONFRAME

Page 22: RxJS Evolved

USING SCHEDULERSObservable.range = function(start, length, scheduler) {

return new Observable((subscriber) => {

return scheduler.schedule(({ index, count }) => {

if (subscriber.isUnsubscribed) { return; }

else if (index >= end) {

subscriber.complete();

} else {

subscriber.next(count);

this.schedule({ index: index + 1, count: count + 1 });

}

}, { index: 0, count: start });

});

}

Page 23: RxJS Evolved

USING SCHEDULERSObservable.fromEvent(“mouseMove”, document.body)

.throttle(1, Scheduler.requestAnimationFrame)

.map(({ pageX, pageY }) => (<div

className=“red-circle”

style={{ top: pageX, left: pageY }} />

))

.subscribe((mouseDiv) => {

React.render(mouseDiv, “#app-container”);

});

Page 24: RxJS Evolved

RXJS NEXT (v5.0.0-alpha)github.com/ReactiveX/RxJS

Page 25: RxJS Evolved

CONTRIBUTORS

BEN LESH ANDRÈ STALTZ OJ KWON

Page 26: RxJS Evolved

github.com/ReactiveX/RxJS/graphs/contributors

Page 27: RxJS Evolved

PRIMARY GOALS★ MODULARITY

★ PERFORMANCE

★ DEBUGGING

★ EXTENSIBILITY

★ SIMPLER UNIT TESTS

Page 28: RxJS Evolved

import Observable from ‘@reactivex/rxjs/Observable’;

import ArrayObservable from

‘@reactivex/rxjs/observables/ArrayObservable’;

import reduce from ‘@reactivex/rxjs/operators/reduce’;

Observable.of = ArrayObservable.of;

Observable.prototype.reduce = reduce;

Observable.of(1, 2, 3, 4, 5)

.reduce((acc, i) => acc * i, 1)

.subscribe((result) => console.log(result));

MODULARITY

Page 29: RxJS Evolved

SPEED

4.3X* FASTER*AVERAGE

(UP TO 11X)

Page 30: RxJS Evolved

50-90% FEWER

ALLOCATIONS

MEMORY

Page 31: RxJS Evolved

10-90% SHORTER

CALL STACKS

DEBUGGING

Page 32: RxJS Evolved

DEBUGGINGFLATMAP EXAMPLE RXJS 4

Page 33: RxJS Evolved

DEBUGGINGFLATMAP EXAMPLE RXJS 5

Page 34: RxJS Evolved

DEBUGGINGSWITCHMAP EXAMPLE RXJS 4

Page 35: RxJS Evolved
Page 36: RxJS Evolved
Page 37: RxJS Evolved
Page 38: RxJS Evolved

DEBUGGINGSWITCHMAP EXAMPLE RXJS 5

Page 39: RxJS Evolved

PERFORMANCE + DEBUGGING

★ SCHEDULERS OVERHAUL

★ CLASS-BASED OPERATORS (“LIFT”)

★ UNIFIED OBSERVER + SUBSCRIPTION

★ FLATTENED DISPOSABLE TREE

★ REMOVE TRY-CATCH FROM INTERNALS

Page 40: RxJS Evolved

FLATMAP VS. LIFT

flatMap<T, R>(selector: (value: T) => Observable<R>): Observable<R>;

lift<T, R>(operator: (subscriber: Observer<T>) => Observer<R>): Observable<R>;

Page 41: RxJS Evolved

FLATMAP

Observable.prototype.map = function map(project) {

var source = this;

return new Observable(function (observer) {

return source.subscribe(

(x) => observer.next(project(x)),

(e) => observer.error(e),

( ) => observer.complete()

);

});

}

★ CLOSURE SCOPE

★ INFLEXIBLE TYPE

★ CLOSURES SHOULD BE ON A PROTOTYPE

Page 42: RxJS Evolved

Observable.prototype.map = function(project) => { return this.lift(new MapOperator(project));}

class MapOperator implements Operator { constructor(project) { this.project = project; } call(observer) { return new MapSubscriber(observer, this.project); }}

class MapSubscriber extends Subscriber { constructor(destination, project) { super(destination); this.project = project; } next(x) { this.destination.next(this.project(x)); }}

★ NO CLOSURES

★ DELEGATES NEW OBSERVABLE TO LIFT

★ USES SUBSCRIBER PROTOTYPE

LIFT

Page 43: RxJS Evolved

EXTENSIBILITY

★ ALLOW SUBCLASSING OBSERVABLE

★ MAINTAIN SUBJECT BI-DIRECTIONALITY

★ FUTURE BACK-PRESSURE SUPPORT?

Page 44: RxJS Evolved

SUBCLASS OBSERVABLEclass MouseObservable extends Observable {

constructor(source, operator) {

this.source = source;

this.operator = operator || ((x) => x);

}

lift(operator) { return new MouseObservable(this, operator); }

trackVelocity() {

return this.lift((destination) => {

return new VelocityScanningSubscriber(destination);

});

}

concatFrictionEvents(coefficientOfKineticFriction) { ... }

}

Page 45: RxJS Evolved

SUBCLASS OBSERVABLEObservable.fromEvent(“mousedown”, document.body)

.flatMap((downEvent) => {

return Observable.fromEvent(“mousemove”, window)

.let(_ => new MouseObservable(this))

.trackVelocity()

.takeUntil(Observable.fromEvent(“mouseup”, window))

.concatFrictionEvents(0.5)

})

.throttle(1, Schedulers.requestAnimationFrame)

.subscribe(({ x, y }) => {

item.style.top = y;

item.style.left = x;

});

Page 46: RxJS Evolved

MAINTAIN TWO-WAY SUBJECTSvar naviSocket = new SocketSubject(“ws://127.0.0.1/navi”)

.map(x => JSON.parse(x.data))

.throttle(100);

naviSocket.subscribe((msg) => {

if (msg == “hey, listen!”) {

naviSocket.next(“go away navi!”);

}

});

Page 47: RxJS Evolved

SIMPLER UNIT TESTSMARBLE DIAGRAMS AS UNIT TESTS

Page 48: RxJS Evolved

SIMPLER UNIT TESTSMARBLE DIAGRAMS AS UNIT TESTS

it('should filter out even values', function() {

var source = hot('--0--1--2--3--4--|');

var expected = '-----1-----3-----|';

expectObservable(source.filter(x => x % 2 == 1)).toBe(expected);

});

Page 49: RxJS Evolved

RXJS NEXT (v5.0.0-alpha)github.com/ReactiveX/RxJS