Post on 10-May-2015
description
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