Cascadia.js: Don't Cross the Streams

Post on 10-May-2015

3,339 views 0 download

Tags:

description

Introduction to the Reactive Extensions for JavaScript at Cascadia JS 2012

transcript

Don’t Cross the Streams…

Matthew Podwysocki

@mattpodwysocki

Callback Hell…

app.get('/index', function (req, res, next) {User.get(req.params.userId, function (err, user) {

if (err) next(err);db.find({user: user.name}, function (err, cursor) {

if (err) next(err);cursor.toArray(function (err, items) {

if (err) next(err);res.send(items);

});});

});}); …and the Pyramid of Doom

The promise of a better future…

tweetsAsync()

.then(function (a) { return usersAsync(a); })

.then(function (b) { return locationAsync(b); })

.done(function (c) { render(); });

What about events?

• What about composition?

• How do I clean up handlers?

• How do I merge streams?

• Or filter?

• Or aggregate?

• Without having a lot of state hanging around?

• The list goes on and on…

In other words…

We cross the streams!

What is it?

• RxJS is…

• a set of types representing asynchronous data streams

• a set of operators over asynchronous data streams

• a set of types to parameterize concurrency

RxJS = Observables + LINQ + Schedulers

Not another flow control library…

Why bother?

var mousedrag = mousedown.selectMany(function (md) {

// calculate offsets when mouse downvar startX = md.offsetX,

startY = md.offsetY;

// calculate diffs until mouse upreturn mousemove.select(function (mm) {

return {left: mm.clientX - startX,top: mm.clientY - startY

};}).takeUntil(mouseup);

});

Rich Composite Events…

var words = Rx.Observable.fromEvent(input, "keyup")

.select(function(x) { return input.value; })

.throttle(500)

.distinctUntilChanged()

.select(function(term) { return search(term); })

.switchLatest();

words.subscribe(function (data) {

// Bind data to the UI

});

Control Flow…

stockTicks

.groupBy(function (tick) { return tick.symbol; })

.selectMany(

function (g) { return g.bufferWithCount(2, 1); },

function (g, b) { return { key: g.key, b: b }; })

.select(function (c) {

return { diff: (c.b[1] – c.b[0]) / c.b[0], symbol: c.key };

})

.where(function (c) { return c.diff > 0.1; })

.select(function (c) {

return { company: c.symbol, increase: c.diff };

});Complex Event Processing…

var sequence = '38,38,40,40,37,39,37,39,66,65';

var keyups = Rx.Observable.fromEvent(document, 'keyup')

.select(function (x) { return x.keyCode; })

.bufferWithCount(10, 10)

.subscribe(function (x) {

var matches = x.join() === sequence;

if (matches) console.log('Konami');

});

What is it?

• RxJS is…

• a set of types representing asynchronous data streams

• a set of operators over asynchronous data streams

• a set of types to parameterize concurrency

RxJS = Observables + LINQ + Schedulers

The Essentials…

Observable = {subscribe :

function (observer) { … }};

Observer = {onNext :

function (data) { … },onError :

function (error) { … },onCompleted :

function () { … }};

Observable

Subscribe

Observer

The Grammar Police…

• Zero or more values

• E.g. events are ∞ sequences

OnError OnCompleted

0 1 2

0 1

0 1 2

0 1 2

* ( | ) ?

• It’s a sequence

• No concurrent

callbacks

• One time termination

First Class Events…

What?

• RxJS is…

• a set of types representing asynchronous data streams

• a set of operators over asynchronous data streams

• a set of types to parameterize concurrency

RxJS = Observables + LINQ + Schedulers

If you know ES5 Array “extras”…

Array

• Querying

• concat

• every

• filter

• map

• reduce

• some

• Subscribing

• forEach

Observable

• Querying

• concat

• all

• where

• select

• aggregate

• any

• Subscribing

• subscribe

… then you know RxJS

Querying Asynchronous Streams

• Observables are data streams

• Hence we can query them like we do with Arrays!

functionreturn

Querying Asynchronous Streams

• Observables are asynchronous

• Hence, they have a notion of time

Limited only by imagination…aggregate

all

amb

any

asObservable

average

buffer

bufferWithCount

bufferWithTime

bufferWithTimeOrCount

catchException

combineLatest

concat

concatObservable

contains

count

create

createWithDisposable

defaultIfEmpty

defer

delay

dematerialize

distinct

disinctUntilChanged

doAction

elementAt

elementAtOrDefault

empty

generate

generateWithAbsoluteTime

generateWithRelativeTime

groupBy

groupByUntil

groupJoin

ignoreElements

interval

join

materialize

max

maxBy

merge

mergeObservable

min

minBy

multicast

never

observeOn

onErrorResumeNext

publish

publishLast

range

refCount

repeat

replay

retry

returnValue

sample

scan

select

selectMany

sequenceEqual

skip

skipLast

skipUntil

skipWhile

start

startWith

subscribe

subscribeOn

sum

switchLatest

take

takeLast

takeLastBuffer

takeUntil

takeWhile

then

throttle

throwException

timeInterval

timeout

timer

using

when

where

window

windowWithCount

windowWithAbsoluteTime

windowWithRelativeTime

zip

Creation operators

create*

empty

fromArray

generate*

never

range

repeat

returnValue

Standard operators

distinct

distinctUntilChanged

groupBy

select

selectMany

skip*

take*

where

Aggregation operators

aggregate

all

any

contains

count

min

max

scan

Error handling operators

catchException

finallyAction

onErrorResumeNext

retry

throwException

using

Complex Event operators

buffer*

groupJoin

join

window*

sample

Orchestration operators

combineLatest

concat

forkJoin

merge

skipUntil

switchLatest

takeUntil

zip

Time based operators

delay

interval

throttle

timeout

timeInterval

timer

timeStamp

What?

• RxJS is…

• a set of types representing asynchronous data streams

• a set of operators over asynchronous data streams

• a set of types to parameterize concurrency

RxJS = Observables + LINQ + Schedulers

The Role of Schedulers…

• Key questions:

• How to run timers?

• Where to produce events?

• Need to synchronize with the UI?

• Providing one answer:

• Schedulers introduce concurrency

• Operators are parameterized by schedulers

• Provides test benefits as well

d = scheduler.schedule(function () {

// Asynchronously// running work

},1000);

Cancellation

Many implementations

Optional time

Testability is King!

var scheduler = new TestScheduler();

var input = scheduler.createColdObservable(

onNext(300, "Cascadia"),

onNext(400, "JS"),

onCompleted(500));

var results = scheduler.startWithCreate(function () {

input.select(function (x) { return x.length; })

});

results.messages.assertEqual(

onNext(300, 8),

onNext(400, 2),

onCompleted(500));

Start using it now

> npm install rx

Node.js

http://rx.codeplex.com/

Open Source

> Install-Package RxJS

NuGet

What’s Next?

• Ongoing work

• Documentation

• Tutorials

• Where’s the vision?

• Scaling

• Distributed

• Merge with Node.js Streams

Cross the Streams…

Matthew Podwysocki

@mattpodwysocki

matthewp@microsoft.com

Credits

• Cross the Streams -https://oshea12566.wordpress.com/2012/02/20/jeep-meeting-and-trail-ride/

• NES Controller - http://en.wikipedia.org/wiki/File:NES-controller.jpg