Top Banner
Introduction to Reactive Extensions without saying “functional” or “reactive” Tetsuharu OHZEKI (April 28, 2016. html5j platform)
34

Introduction to Reactive Extensions without saying functional reactive

Apr 14, 2017

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Introduction to Reactive Extensions without saying functional reactive

Introduction to

Reactive Extensionswithout saying “functional” or “reactive”

Tetsuharu OHZEKI(April 28, 2016. html5j platform)

Page 2: Introduction to Reactive Extensions without saying functional reactive

About me

Tetsuharu OHZEKI

twitter: saneyuki_s

Open Source Developer

Mozilla Committer (Firefox, Servo as reviewer)

ReactiveX/RxJS

And some others… (whatwg html, etc)

Working at VOYAGE GROUP, inc.

My main work is to develop an advertising management system

with using TypeScript, babel compiler, React, and RxJS.

Page 3: Introduction to Reactive Extensions without saying functional reactive

https://youtu.be/COviCoUtwx4

Page 4: Introduction to Reactive Extensions without saying functional reactive

I don’t talk about…

Functional Programming

Functional Reactive Programming (FRP)

Fiber-Reinforced Plastics (FRP)

Enterprise Application Architecture Pattern Read “Microsoft .NET - Architecting Applications for the Enterprise, 2nd

Edition (Dino Esposito)”. It’s very nice.

Recommend to use RxJS

Page 5: Introduction to Reactive Extensions without saying functional reactive

It is sometimes called “functional reactive

programming” but this is a misnomer.

ReactiveX may be functional, and it may be

reactive, but “functional reactive

programming” is a different animal. One

main point of difference is that functional

reactive programming operates on values

that change continuously over time, while

ReactiveX operates on discrete values that

are emitted over time.

http://reactivex.io/intro.html

Page 6: Introduction to Reactive Extensions without saying functional reactive

I’ll talk about…

Programming style

for application engineering

in practice

Page 7: Introduction to Reactive Extensions without saying functional reactive

Events are everywhere…

Data Mutation

Domain Event

File I/O

Network I/O

Network Status

User Input

Geolocation

Battery

Memory Pressure

Device Orientation

Ambient light

Cluster Node’s status

Server monitoring

Logging

Page 8: Introduction to Reactive Extensions without saying functional reactive

const subject =

new SomeEventEmitter();

const flag1 = false;

const flag2 = Date.now();

const flag3 = false;

subject.on('bar', (e) => {

flag1 = !flag1;

});

subject.on('foo', (e) => {

const now = Date.now();

if (now > (flag2 + 100)) {

flag2 = now;

flag3 = true;

}

});

subject.on('hogefuga', (e) => {

if (flag1 && flag3) {

alert('hello!');

}

});

Page 9: Introduction to Reactive Extensions without saying functional reactive
Page 10: Introduction to Reactive Extensions without saying functional reactive

Rx came from C#…

Originated in “Microsoft Live Labs Volta” (2008)

Designed by Erik Meijer and his team

Reactive Extensions in .NET (2009~)

“LINQ to Events”

RxJava is open sourced by Netflix (2012)

By Jefer Husain

https://twitter.com/jhusain

https://vimeo.com/110554082

Page 11: Introduction to Reactive Extensions without saying functional reactive

Rx key components

Observable

Operator

Subject

Scheduler

Page 12: Introduction to Reactive Extensions without saying functional reactive

Pull Push

One T Promise<T>

Zero-Infinity Iterable<T> Observable<T>

Observable

Page 13: Introduction to Reactive Extensions without saying functional reactive

Operator

http://reactivex.io/documentation/operators/map.html

Page 14: Introduction to Reactive Extensions without saying functional reactive

Subject

http://reactivex.io/documentation/subject.html

Page 15: Introduction to Reactive Extensions without saying functional reactive

Scheduler

Event Loop

Scheduler

Page 16: Introduction to Reactive Extensions without saying functional reactive

Programming Key Points

Repeat these until you get an expected final value

1. Define a “source” of an event as Observable

2. Apply Operator, and create a new “check-point”

Observable

Scheduler can control “timing” to deliver a value

Page 17: Introduction to Reactive Extensions without saying functional reactive

Compose a new operator for you

// Filter sequence, then transform from T to U.

function filterMap<T, U>(source: Rx.Observable<T>,

filterFn: (v: T) => boolean,

mapFn: (v: T) => U): Rx.Observable<U>{

return source.filter(filterFn).map(mapFn);

}

const foo = filterMap(bar);

Page 18: Introduction to Reactive Extensions without saying functional reactive

const subject =

new SomeEventEmitter();

const flag1 = false;

const flag2 = Date.now();

const flag3 = false;

subject.on('bar', function(e) {

flag1 = !flag1;

});

subject.on('foo', function(e) {

const now = Date.now();

if (now > (flag2 + 100)) {

flag2 = now;

flag3 = true;

}

});

subject.on('hogefuga', function(e) {

if (flag1 && flag3) {

alert('hello!');

}

});

Page 19: Introduction to Reactive Extensions without saying functional reactive

const bar = Observable.fromEvent(subject, 'bar')

.scan((flag) => !flag, false)

.filter((ok) => ok);

const foo = Observable.fromEvent(subject, 'foo')

.debounce(100);

Observable.fromEvent(subject, 'hogefuga')

.withLatestFrom(bar, foo, () => alert('hello!'));

Page 20: Introduction to Reactive Extensions without saying functional reactive

alert()withLatestFrom

filterscan

bar

debounce(100)

foo

barfoo

Page 21: Introduction to Reactive Extensions without saying functional reactive

See the implementation: scan()

Page 22: Introduction to Reactive Extensions without saying functional reactive

See the implementation: scan

https://github.com/ReactiveX/rxjs/blob/a3ec896/src/operator/scan.ts

Page 23: Introduction to Reactive Extensions without saying functional reactive

alert()withLatestFrom

filterscan

bar

debounce(100)

foo

barfoo

Page 24: Introduction to Reactive Extensions without saying functional reactive

Rx is just “advanced” observer pattern

Sort interfaces & calling convention

Define many middle-relay object as “Operator”

Page 25: Introduction to Reactive Extensions without saying functional reactive

Pull Push

Zero-Infinity Iterable<T> Observable<T>

Page 26: Introduction to Reactive Extensions without saying functional reactive

Duality (Iterable vs Observable)

Pull (e.g. Iterable)

Calling “ancestor” data source from “descendant” consumer.

Push (e.g. Observable)Calling “descendant” consumer from

“ancestor” data source

data source

consumer

Pull

Push

Page 27: Introduction to Reactive Extensions without saying functional reactive

e.g. Iterable + operator extensions

(Let’s create!)

const exiterable = ExIterable.create(iterable);

const result = exiterable

.filter((v) => v % 2 === 0)

.map((v) => v * 2);

const {done, value} = result.next();

for (let value of result) { … } // caution: blocking

Page 28: Introduction to Reactive Extensions without saying functional reactive

e.g. Iterable -> Observable (Sync)

// This push all values as sync

const iterableToObservable = Rx.Observable.create((subscriber) => {

for (const item of iterable) { // This need be blocking

subscriber.next(item);

}

subscriber.complete();

});

// This cause blocking…

iterableToObservable.subscribe((v) => console.log(v));

Page 29: Introduction to Reactive Extensions without saying functional reactive

e.g. Observable -> Iterable (Sync)

class ObservableToIter {

constructor(source) {

this._cache = cache;

source.subscribe((v) => this._cache.push(v));

}

next() {

const done = this._cache.length > 0;

let value = undefined;

if (done) {

value = this._cache.shift();

}

return { done, value, };

}

[Symbol.iterator]() { return this; }

}

const iter = new ObservableToIter(source);

iter.next();

Limitations (Problems)

On consuming first value or

initializing the converter, we

need to get all value from

sequence.

If observable returns value

async, we don't transform

observable to iterable, or wait

to complete observable with

blocking!

If observable is infinite

sequence, we cannot return to

consumer.

Page 30: Introduction to Reactive Extensions without saying functional reactive

https://twitter.com/headinthebox/status/669963949027160064

Page 31: Introduction to Reactive Extensions without saying functional reactive

e.g. Async Iteration (proposal for ECMA262)

const result: Promise<IteratorResult<T>>

= asyncIter.next();

result.then((done, value) => console.log(done, value));

for await (let value of asyncIter) { // not blocking

// blah, blah, blah

}

Page 32: Introduction to Reactive Extensions without saying functional reactive

e.g. AsyncIterable -> Observable (PoC)

// This can push all values async

const asyncIterableToObservable = Rx.Observable.create((subscriber) => {

for await (const item of asyncIterable) { // This need not to be blocking

subscriber.next(item);

}

subscriber.complete();

});

asyncIterableToObservable.subscribe((v) => console.log(v));

Page 33: Introduction to Reactive Extensions without saying functional reactive

e.g. Observable -> AsyncIterable (PoC)class ObservableToIter {

constructor(source) {

this._buffer = [];

this._resolverCache = [];

this._done = false;

this._current = 0;

source.subscribe((v) => {

this._buffer.push({ ok: true, value: v, });

const lastIndex = this._buffer.length - 1;

const resolver = this._resolverCache[lastIndex];

if (resolver !== undefined) {

resolver({ done: this._done, value: v, });

this._resolverCache[lastIndex] = undefined;

}

}, () => {}, () => {

this._done = true;

for (const resolver of this._resolverCache) {

if (resolver === undefined) { continue; }

resolver({

done: true,

});

}

this._resolverCache = [];

});

}

next() {

const done = this._done;

if (done) {

return Promise.resolve({ done });

}

const current = this._current;

this._current++;

const result = this._buffer[current];

if (result !== undefined && result.ok) {

return Promise.resolve({

done,

value: result.value,

});

}

else {

return new Promise((resolve) => {

this._resolverCache[current] = resolve;

});

}

}

[System.asyncIterator]() { return this; }

}

const source = Rx.Observable.create((o) => {

const buffer: any = [];

for (const i of [1, 2, 3, 4, 5]) {

buffer.push(new Promise((r) => {

window.setTimeout(() => {

r();

o.next(i);

}, i * 1000);

}));

}

Promise.all(buffer).then(() => o.complete());

});

const iter = new ObservableToIter(source);

await iter.next() // done: false, value: 1

await iter.next(); // done: false, value: 2

await iter.next(); // done: false, value: 3

await iter.next(); // done: false, value: 4

await iter.next(); // done: false, value: 5

await iter.next(); // done: false, value: undefined

Page 34: Introduction to Reactive Extensions without saying functional reactive

Summary

Push/Pull is duality of APIs which treats

sequence, set, or collection.

Which is more suitable for your case?

Rx is advanced observer pattern

implementation that provides highly

composable push APIs