SlideShare a Scribd company logo
RxJS In-Depth
(Formerly a talk called
“Reactive Streams in Angular 1 and 2”)
We had a last-minute
pivot on talk content,
because Jeff Cross and
Rob Wormald wanted to
ruin my week last week.
Ben Lesh
Senior UI Engineer
Edge Developer Experience
RxJS Next
http://github.com/ReactiveX/RxJS
“RxJS Next”
is now
RxJS 5.0.0-alpha
RxJS 5 is community
driven
Spear-headed by contributors at Netflix, Google
and Microsoft. With many other contributors
under the ReactiveX community banner.
RxJS 5 Goals
• Performance
• Improved debugging
• ES7 observable spec alignment
Performance
• Decisions were guided by performance testing
• Tried out 4-5 different architectures in the
beginning
• > 120 micro performance tests
• ~ 10 macro performance tests around common
scenarios and bottlenecks
RxJS 5 operators are
4.3x faster on average
Call-stack depth and debugging
was a common complaint in older
versions of RxJS
RxJS 4
RxJS 5
Thanks in huge part to
contributions from
Paul Taylor OJ Kwon
André Staltz Jeff Cross
… really every one of our
contributors.
https://github.com/ReactiveX/RxJS/graphs/contributors
Thanks to guidance from
Matt Podwysocki Jafar Husain Erik Meijer
Ben Christensen George Campbell Aaron Tull
we’re closing in on beta
in the next month or so
What is RxJS?
• Reactive programming
• Treating events as collections
• Manipulating sets of events with ”operators”
“RxJS is LoDash or Underscore for async.”
Angular 2 is using
RxJS 5 Observables
for async
Angular has traditionally
used Promises for async
Promises
• Read-only view to a single future value
• Success and error semantics via .then()
• Not lazy. By the time you have a promise, it’s on
its way to being resolved.
• Immutable and uncancellable. Your promise will
resolve or reject, and only once.
Observable
• “Streams” or sets
• Of any number of things
• Over any amount of time
• Lazy. Observables will not generate values via an
underlying producer until they’re subscribed to.
• Can be “unsubscribed” from. This means the
underlying producer can be told to stop and even tear
down.
Both Promises and Observables
are built to solve problems
around async
(to avoid “callback hell”)
Types of async in modern
web applications
• DOM events
• Animations
• AJAX
• WebSockets
• SSE
• Alternative inputs (voice, joystick, etc)
Promises only really make
sense for one of these
• DOM events (0-N values)
• Animations (cancelable)
• AJAX (1 value)
• WebSockets (0-N values)
• SSE (0-N values)
• Alternative inputs (0-N values)
… except when they don’t
• Single page applications commonly prepare data
via AJAX for each view shown
• When the view changes, the next view probably
doesn’t care about the previous view’s data
• Fortunately, XHRs can be aborted!
• …but promise-based AJAX implementations
cannot be aborted, because promises cannot be
cancelled.*
So how do we go from
Promises to
Observables?
They have some similar
semantics
then x. (valueFn, errorFn);subscribe
They have some similar
semantics
x.subscribe(valueFn, errorFn);, completeFn
Observable also has
cancellation semantics!
let sub = x.subscribe(valueFn, errorFn, completeFn);
// ...some time later
sub.unsubscribe();
Creating Observables is
similar to creating
Promises
creating a Promise
let p = new Promise((resolve, reject) => {
doAsyncThing((err, value) => {
if (err) {
reject(err);
} else {
resolve(value);
}
});
});
creating an Observable
let o = new Observable(observer => {
doAsyncThing((err, value) => {
if (err) {
observer.error(err);
} else {
observer.next(value);
observer.complete();
}
});
});
if the producer’s resource
allows cancellation,
we can handle that here
let o = new Observable(observer => {
const token = doAsyncThing((err, value) => {
if (err) {
observer.error(err);
} else {
observer.next(value);
observer.complete();
}
});
});
const token
return () => {
cancelAsyncThing(token);
};
when you call o.subscribe()
let o = new Observable(observer => {
const token = doAsyncThing((err, value) => {
if (err) {
observer.error(err);
} else {
observer.next(value);
observer.complete();
}
});
return () => {
cancelAsyncThing(token);
};
});
observer => {
const token = doAsyncThing((err, value) => {
if (err) {
observer.error(err);
} else {
observer.next(value);
observer.complete();
}
});
return () => {
};
});
when you call
subscription.unsubscribe()
let o = new Observable(observer => {
const token = doAsyncThing((err, value) => {
if (err) {
observer.error(err);
} else {
observer.next(value);
observer.complete();
}
});
return () => {
cancelAsyncThing(token);
};
});
return () => {
cancelAsyncThing(token);
};
Don’t worry... you’re
unlikely to be creating
your own Observables
Observable creation
helpers in RxJS
• Observable.of(value, value2, value3, …)
• Observable.from(promise/iterable/observable)
• Observable.fromEvent(item, eventName)
• Angular’s HTTP and Realtime Data services
• Many community-driven RxJS modules and
libraries
Error Handling in
Observables is also
similar to Promise
catch
myPromise.catch(error => {
if (error instanceof OkayError) {
return Promise.resolve(‘okay’);
} else {
throw error;
}
});
catch
myObservable.catch(error => {
if (error instanceof OkayError) {
return Observable.of(‘okay’);
} else {
throw error;
}
});
finally
(some promise impls)
myPromise.finally(() => {
console.log(‘done’);
});
finally
myObservable.finally(() => {
console.log(‘done’);
});
Observables can be “retried”
myObservable.retry(3);
myObservable.retryWhen(errors =>
errors.delay(3000));
Quick Recap on
Observable
An observable is a set of any number of things over
any amount of time.
Quick Recap on
Observable
All values are pushed to the nextHandler
observable.subscribe(nextHandler);
Quick Recap on
Observable
The errorHandler is called if the producer
experiences an error
observable.subscribe(nextHandler, errorHandler);
Quick Recap on
Observable
The completionHandler is called when the producer
completes successfully
observable.subscribe(nextHandler, errorHandler, completionHandler);
Quick Recap on
Observable
Observables are lazy. It doesn’t start producing
data until subscribe() is called.
observable.subscribe(nextHandler, errorHandler, completionHandler);
Quick Recap on
Observable
subscribe() returns a subscription, on which a
consumer can call unsubscribe() to cancel the
subscription and tear down the producer
let sub = observable.subscribe(nextHandler, errorHandler, completionHandler);
sub.unsubscribe();
What are “operators”?
They’re methods on Observable that allow you to
compose new observables.
How operators work
let result = source.myOperator();
result is an Observable, that when subscribed to,
subscribes to source, then tranforms it’s values in
some way and emits them.
How operators work
subscription.unsubscribe();
when unsubscribe() is called on that
subscription, the unsubscription logic from both
result and source are called.
How operators work
• Operators pass each value from one operator to
the next, before proceeding to the next value in
the set.*
• This is different from array operators (think map
and filter) which will process the entire array at
each step.
• *This can be changed with Schedulers.
Array filter, map, reduce
Observable filter, map, reduce
simple operators
• map()
• filter()
• reduce()
• first()
• last()
• single()
• elementAt()
• toArray()
• isEmpty()
• take()
• skip()
• startWith()
• and many more…
merging and joining operators
• merge
• mergeMap (flatMap)
• concat
• concatMap
• switch
• switchMap
• combineLatest
• withLatestFrom
• zip
• forkJoin
• expand
splitting and grouping operators
• groupBy
• window
• partition
buffering strategy operators
• buffer
• throttle
• debounce
• sample
With ES7 function bind,
you can roll your own*
(*coming soon to TypeScript?)
“hot” vs “cold” observables
• Observables are “cold” by default
• “Cold” observables create a new producer each
time a consumer subscribes to them
• “Hot” observables share a single producer with
every consumer that subscribes to them.
Multiplexed WebSocket
• Connect to a web socket server
• For each data stream
• send a subscription message to the server
• filter out responses from the server
• when done, send an unsubscription message.
• Ideally, the socket is only open while you require data
from it.
Multiplexed WebSocket
• RECONNECTION?!
• maintain a state of all of the multiplexed data
streams your views need.
• check to see when you’re able to reconnect
• reconnect the socket
• once the socket is reopened, send all of the
subscription messages again
Create an Observable
that wraps a WebSocket
It will create the WebSocket
when you subscribe()
It emits messages events
that arrive on the WebSocket
And when it unsubscribes,
it will tear down the WebSocket!
“Share” to make it “hot”…
We don’t want each subscription
creating it’s own websocket.
Create an Observable
that wraps our
Socket Observable
filter the messages
from the Socket Observable
to what you need
and subscribe
Send a message to
the server to start getting
the data over the socket
on unsubscribe,
tell the server
to stop sending data
and unsubscribe
from the socket observable
Add a retryWhen to retry the whole thing
if something goes wrong with the multiplexed observable
“share” the observable to make it “hot”,
so many consumers can share this producer.
Example Time!
Never trust anyone with
only good things to say
about their
library/framework.
What’s bad in RxJS?
• “Zalgo”.. don’t use mutable outer scoped
variables in your operators or subscriptions!
• Unbounded buffers! The zip operator in particular
is dangerous here.
• Too many operators to remember.
Twitter: @benlesh
github: blesh
ben@benlesh.com
GOOD: Comments.
BETTER: Questions.
BEST: Corrections!
Thank you!

More Related Content

What's hot

Intro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaIntro to Functional Programming with RxJava
Intro to Functional Programming with RxJava
Mike Nakhimovich
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
Brainhub
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
Igor Lozynskyi
 
RxJS Operators - Real World Use Cases (FULL VERSION)
RxJS Operators - Real World Use Cases (FULL VERSION)RxJS Operators - Real World Use Cases (FULL VERSION)
RxJS Operators - Real World Use Cases (FULL VERSION)
Tracy Lee
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
cacois
 
The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016
Frank Lyaruu
 
Angular and The Case for RxJS
Angular and The Case for RxJSAngular and The Case for RxJS
Angular and The Case for RxJS
Sandi Barr
 
Connect S3 with Kafka using Akka Streams
Connect S3 with Kafka using Akka Streams Connect S3 with Kafka using Akka Streams
Connect S3 with Kafka using Akka Streams
Seiya Mizuno
 
Luis Atencio on RxJS
Luis Atencio on RxJSLuis Atencio on RxJS
Luis Atencio on RxJS
Luis Atencio
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
Domenic Denicola
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
Tomáš Kypta
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
Tomáš Kypta
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsLeonardo Borges
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
Tomáš Kypta
 
RxJava for Android - GDG DevFest Ukraine 2015
RxJava for Android - GDG DevFest Ukraine 2015RxJava for Android - GDG DevFest Ukraine 2015
RxJava for Android - GDG DevFest Ukraine 2015
Constantine Mars
 
Functional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJSFunctional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJS
Oswald Campesato
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
Yakov Fain
 
Callbacks and control flow in Node js
Callbacks and control flow in Node jsCallbacks and control flow in Node js
Callbacks and control flow in Node js
Thomas Roch
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
jnewmanux
 
Realm Mobile Database - An Introduction
Realm Mobile Database - An IntroductionRealm Mobile Database - An Introduction
Realm Mobile Database - An Introduction
Knoldus Inc.
 

What's hot (20)

Intro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaIntro to Functional Programming with RxJava
Intro to Functional Programming with RxJava
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
 
RxJS Operators - Real World Use Cases (FULL VERSION)
RxJS Operators - Real World Use Cases (FULL VERSION)RxJS Operators - Real World Use Cases (FULL VERSION)
RxJS Operators - Real World Use Cases (FULL VERSION)
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016The Road To Reactive with RxJava JEEConf 2016
The Road To Reactive with RxJava JEEConf 2016
 
Angular and The Case for RxJS
Angular and The Case for RxJSAngular and The Case for RxJS
Angular and The Case for RxJS
 
Connect S3 with Kafka using Akka Streams
Connect S3 with Kafka using Akka Streams Connect S3 with Kafka using Akka Streams
Connect S3 with Kafka using Akka Streams
 
Luis Atencio on RxJS
Luis Atencio on RxJSLuis Atencio on RxJS
Luis Atencio on RxJS
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
RxJava for Android - GDG DevFest Ukraine 2015
RxJava for Android - GDG DevFest Ukraine 2015RxJava for Android - GDG DevFest Ukraine 2015
RxJava for Android - GDG DevFest Ukraine 2015
 
Functional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJSFunctional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJS
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
 
Callbacks and control flow in Node js
Callbacks and control flow in Node jsCallbacks and control flow in Node js
Callbacks and control flow in Node js
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Realm Mobile Database - An Introduction
Realm Mobile Database - An IntroductionRealm Mobile Database - An Introduction
Realm Mobile Database - An Introduction
 

Viewers also liked

RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015
Ben Lesh
 
Angular2 + rxjs
Angular2 + rxjsAngular2 + rxjs
Angular2 + rxjs
Christoffer Noring
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
stefanmayer13
 
ReactiveX-SEA
ReactiveX-SEAReactiveX-SEA
ReactiveX-SEAYang Yang
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolved
trxcllnt
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-Java
Kasun Indrasiri
 
Building modular enterprise scale angular js applications
Building modular enterprise scale angular js applicationsBuilding modular enterprise scale angular js applications
Building modular enterprise scale angular js applications
Jonathan Fontanez
 
Observables in angular2
Observables in angular2Observables in angular2
Observables in angular2
Filip Bruun Bech-Larsen
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
名辰 洪
 
Angular 2 observables
Angular 2 observablesAngular 2 observables
Angular 2 observables
Geoffrey Filippi
 
Mini training - Reactive Extensions (Rx)
Mini training - Reactive Extensions (Rx)Mini training - Reactive Extensions (Rx)
Mini training - Reactive Extensions (Rx)
Betclic Everest Group Tech Team
 
Angular2 rxjs
Angular2 rxjsAngular2 rxjs
Angular2 rxjs
Christoffer Noring
 
FRP with Ractive and RxJS
FRP with Ractive and RxJSFRP with Ractive and RxJS
FRP with Ractive and RxJS
Alfonso Garcia-Caro
 
Progressive Web Apps
Progressive Web AppsProgressive Web Apps
Progressive Web Apps
Kevin Dantas
 
Programação reativa com RxJS e Angular
Programação reativa com RxJS e AngularProgramação reativa com RxJS e Angular
Programação reativa com RxJS e Angular
Wendel Nascimento
 
Add Some Fun to Your Functional Programming With RXJS
Add Some Fun to Your Functional Programming With RXJSAdd Some Fun to Your Functional Programming With RXJS
Add Some Fun to Your Functional Programming With RXJS
Ryan Anklam
 
Reactive programming
Reactive programmingReactive programming
Reactive programming
Sunscrapers
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
Viliam Elischer
 
Functional Reactive Angular 2
Functional Reactive Angular 2 Functional Reactive Angular 2
Functional Reactive Angular 2
Tomasz Bak
 

Viewers also liked (20)

RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015
 
Angular2 + rxjs
Angular2 + rxjsAngular2 + rxjs
Angular2 + rxjs
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
 
ReactiveX-SEA
ReactiveX-SEAReactiveX-SEA
ReactiveX-SEA
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolved
 
Rxjs ppt
Rxjs pptRxjs ppt
Rxjs ppt
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-Java
 
Building modular enterprise scale angular js applications
Building modular enterprise scale angular js applicationsBuilding modular enterprise scale angular js applications
Building modular enterprise scale angular js applications
 
Observables in angular2
Observables in angular2Observables in angular2
Observables in angular2
 
You will learn RxJS in 2017
You will learn RxJS in 2017You will learn RxJS in 2017
You will learn RxJS in 2017
 
Angular 2 observables
Angular 2 observablesAngular 2 observables
Angular 2 observables
 
Mini training - Reactive Extensions (Rx)
Mini training - Reactive Extensions (Rx)Mini training - Reactive Extensions (Rx)
Mini training - Reactive Extensions (Rx)
 
Angular2 rxjs
Angular2 rxjsAngular2 rxjs
Angular2 rxjs
 
FRP with Ractive and RxJS
FRP with Ractive and RxJSFRP with Ractive and RxJS
FRP with Ractive and RxJS
 
Progressive Web Apps
Progressive Web AppsProgressive Web Apps
Progressive Web Apps
 
Programação reativa com RxJS e Angular
Programação reativa com RxJS e AngularProgramação reativa com RxJS e Angular
Programação reativa com RxJS e Angular
 
Add Some Fun to Your Functional Programming With RXJS
Add Some Fun to Your Functional Programming With RXJSAdd Some Fun to Your Functional Programming With RXJS
Add Some Fun to Your Functional Programming With RXJS
 
Reactive programming
Reactive programmingReactive programming
Reactive programming
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
 
Functional Reactive Angular 2
Functional Reactive Angular 2 Functional Reactive Angular 2
Functional Reactive Angular 2
 

Similar to RxJS In-Depth - AngularConnect 2015

Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular
Jalpesh Vadgama
 
Streamlining with rx
Streamlining with rxStreamlining with rx
Streamlining with rx
Akhil Dad
 
Reactive programming with rx java
Reactive programming with rx javaReactive programming with rx java
Reactive programming with rx java
CongTrung Vnit
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
Rick Warren
 
Reactive programming in Angular 2
Reactive programming in Angular 2Reactive programming in Angular 2
Reactive programming in Angular 2
Yakov Fain
 
RxJava2 Slides
RxJava2 SlidesRxJava2 Slides
RxJava2 Slides
YarikS
 
RxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMixRxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMix
Tracy Lee
 
Reactive Streams and RxJava2
Reactive Streams and RxJava2Reactive Streams and RxJava2
Reactive Streams and RxJava2
Yakov Fain
 
Journey into Reactive Streams and Akka Streams
Journey into Reactive Streams and Akka StreamsJourney into Reactive Streams and Akka Streams
Journey into Reactive Streams and Akka Streams
Kevin Webber
 
Akka-demy (a.k.a. How to build stateful distributed systems) I/II
 Akka-demy (a.k.a. How to build stateful distributed systems) I/II Akka-demy (a.k.a. How to build stateful distributed systems) I/II
Akka-demy (a.k.a. How to build stateful distributed systems) I/II
Peter Csala
 
RxJava@Android
RxJava@AndroidRxJava@Android
RxJava@Android
Maxim Volgin
 
Springone2gx 2014 Reactive Streams and Reactor
Springone2gx 2014 Reactive Streams and ReactorSpringone2gx 2014 Reactive Streams and Reactor
Springone2gx 2014 Reactive Streams and Reactor
Stéphane Maldini
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
Savvycom Savvycom
 
Rxandroid
RxandroidRxandroid
Rxandroid
Thinh Thanh
 
RxAndroid
RxAndroidRxAndroid
RxAndroid
Thinh Thanh
 
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYCBuilding a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Konrad Malawski
 
Saving lives with rx java
Saving lives with rx javaSaving lives with rx java
Saving lives with rx java
Shahar Barsheshet
 
RxJava 2 Reactive extensions for the JVM
RxJava 2  Reactive extensions for the JVMRxJava 2  Reactive extensions for the JVM
RxJava 2 Reactive extensions for the JVM
Netesh Kumar
 
Akka in Production - ScalaDays 2015
Akka in Production - ScalaDays 2015Akka in Production - ScalaDays 2015
Akka in Production - ScalaDays 2015
Evan Chan
 
Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2
JollyRogers5
 

Similar to RxJS In-Depth - AngularConnect 2015 (20)

Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular
 
Streamlining with rx
Streamlining with rxStreamlining with rx
Streamlining with rx
 
Reactive programming with rx java
Reactive programming with rx javaReactive programming with rx java
Reactive programming with rx java
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
 
Reactive programming in Angular 2
Reactive programming in Angular 2Reactive programming in Angular 2
Reactive programming in Angular 2
 
RxJava2 Slides
RxJava2 SlidesRxJava2 Slides
RxJava2 Slides
 
RxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMixRxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMix
 
Reactive Streams and RxJava2
Reactive Streams and RxJava2Reactive Streams and RxJava2
Reactive Streams and RxJava2
 
Journey into Reactive Streams and Akka Streams
Journey into Reactive Streams and Akka StreamsJourney into Reactive Streams and Akka Streams
Journey into Reactive Streams and Akka Streams
 
Akka-demy (a.k.a. How to build stateful distributed systems) I/II
 Akka-demy (a.k.a. How to build stateful distributed systems) I/II Akka-demy (a.k.a. How to build stateful distributed systems) I/II
Akka-demy (a.k.a. How to build stateful distributed systems) I/II
 
RxJava@Android
RxJava@AndroidRxJava@Android
RxJava@Android
 
Springone2gx 2014 Reactive Streams and Reactor
Springone2gx 2014 Reactive Streams and ReactorSpringone2gx 2014 Reactive Streams and Reactor
Springone2gx 2014 Reactive Streams and Reactor
 
Reactive programming with RxAndroid
Reactive programming with RxAndroidReactive programming with RxAndroid
Reactive programming with RxAndroid
 
Rxandroid
RxandroidRxandroid
Rxandroid
 
RxAndroid
RxAndroidRxAndroid
RxAndroid
 
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYCBuilding a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
Building a Reactive System with Akka - Workshop @ O'Reilly SAConf NYC
 
Saving lives with rx java
Saving lives with rx javaSaving lives with rx java
Saving lives with rx java
 
RxJava 2 Reactive extensions for the JVM
RxJava 2  Reactive extensions for the JVMRxJava 2  Reactive extensions for the JVM
RxJava 2 Reactive extensions for the JVM
 
Akka in Production - ScalaDays 2015
Akka in Production - ScalaDays 2015Akka in Production - ScalaDays 2015
Akka in Production - ScalaDays 2015
 
Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2Intro to Reactive Thinking and RxJava 2
Intro to Reactive Thinking and RxJava 2
 

Recently uploaded

Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Product School
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 

Recently uploaded (20)

Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 

RxJS In-Depth - AngularConnect 2015

  • 1. RxJS In-Depth (Formerly a talk called “Reactive Streams in Angular 1 and 2”)
  • 2. We had a last-minute pivot on talk content, because Jeff Cross and Rob Wormald wanted to ruin my week last week.
  • 3. Ben Lesh Senior UI Engineer Edge Developer Experience
  • 6. RxJS 5 is community driven Spear-headed by contributors at Netflix, Google and Microsoft. With many other contributors under the ReactiveX community banner.
  • 7. RxJS 5 Goals • Performance • Improved debugging • ES7 observable spec alignment
  • 8. Performance • Decisions were guided by performance testing • Tried out 4-5 different architectures in the beginning • > 120 micro performance tests • ~ 10 macro performance tests around common scenarios and bottlenecks
  • 9. RxJS 5 operators are 4.3x faster on average
  • 10. Call-stack depth and debugging was a common complaint in older versions of RxJS
  • 13. Thanks in huge part to contributions from Paul Taylor OJ Kwon André Staltz Jeff Cross
  • 14. … really every one of our contributors. https://github.com/ReactiveX/RxJS/graphs/contributors
  • 15. Thanks to guidance from Matt Podwysocki Jafar Husain Erik Meijer Ben Christensen George Campbell Aaron Tull
  • 16. we’re closing in on beta in the next month or so
  • 17. What is RxJS? • Reactive programming • Treating events as collections • Manipulating sets of events with ”operators”
  • 18. “RxJS is LoDash or Underscore for async.”
  • 19. Angular 2 is using RxJS 5 Observables for async
  • 20. Angular has traditionally used Promises for async
  • 21. Promises • Read-only view to a single future value • Success and error semantics via .then() • Not lazy. By the time you have a promise, it’s on its way to being resolved. • Immutable and uncancellable. Your promise will resolve or reject, and only once.
  • 22. Observable • “Streams” or sets • Of any number of things • Over any amount of time • Lazy. Observables will not generate values via an underlying producer until they’re subscribed to. • Can be “unsubscribed” from. This means the underlying producer can be told to stop and even tear down.
  • 23. Both Promises and Observables are built to solve problems around async (to avoid “callback hell”)
  • 24. Types of async in modern web applications • DOM events • Animations • AJAX • WebSockets • SSE • Alternative inputs (voice, joystick, etc)
  • 25. Promises only really make sense for one of these • DOM events (0-N values) • Animations (cancelable) • AJAX (1 value) • WebSockets (0-N values) • SSE (0-N values) • Alternative inputs (0-N values)
  • 26. … except when they don’t • Single page applications commonly prepare data via AJAX for each view shown • When the view changes, the next view probably doesn’t care about the previous view’s data • Fortunately, XHRs can be aborted! • …but promise-based AJAX implementations cannot be aborted, because promises cannot be cancelled.*
  • 27. So how do we go from Promises to Observables?
  • 28. They have some similar semantics then x. (valueFn, errorFn);subscribe
  • 29. They have some similar semantics x.subscribe(valueFn, errorFn);, completeFn
  • 30. Observable also has cancellation semantics! let sub = x.subscribe(valueFn, errorFn, completeFn); // ...some time later sub.unsubscribe();
  • 31. Creating Observables is similar to creating Promises
  • 32. creating a Promise let p = new Promise((resolve, reject) => { doAsyncThing((err, value) => { if (err) { reject(err); } else { resolve(value); } }); });
  • 33. creating an Observable let o = new Observable(observer => { doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } }); });
  • 34. if the producer’s resource allows cancellation, we can handle that here let o = new Observable(observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } }); }); const token return () => { cancelAsyncThing(token); };
  • 35. when you call o.subscribe() let o = new Observable(observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } }); return () => { cancelAsyncThing(token); }; }); observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } }); return () => { }; });
  • 36. when you call subscription.unsubscribe() let o = new Observable(observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } }); return () => { cancelAsyncThing(token); }; }); return () => { cancelAsyncThing(token); };
  • 37. Don’t worry... you’re unlikely to be creating your own Observables
  • 38. Observable creation helpers in RxJS • Observable.of(value, value2, value3, …) • Observable.from(promise/iterable/observable) • Observable.fromEvent(item, eventName) • Angular’s HTTP and Realtime Data services • Many community-driven RxJS modules and libraries
  • 39. Error Handling in Observables is also similar to Promise
  • 40. catch myPromise.catch(error => { if (error instanceof OkayError) { return Promise.resolve(‘okay’); } else { throw error; } });
  • 41. catch myObservable.catch(error => { if (error instanceof OkayError) { return Observable.of(‘okay’); } else { throw error; } });
  • 42. finally (some promise impls) myPromise.finally(() => { console.log(‘done’); });
  • 44. Observables can be “retried” myObservable.retry(3); myObservable.retryWhen(errors => errors.delay(3000));
  • 45. Quick Recap on Observable An observable is a set of any number of things over any amount of time.
  • 46. Quick Recap on Observable All values are pushed to the nextHandler observable.subscribe(nextHandler);
  • 47. Quick Recap on Observable The errorHandler is called if the producer experiences an error observable.subscribe(nextHandler, errorHandler);
  • 48. Quick Recap on Observable The completionHandler is called when the producer completes successfully observable.subscribe(nextHandler, errorHandler, completionHandler);
  • 49. Quick Recap on Observable Observables are lazy. It doesn’t start producing data until subscribe() is called. observable.subscribe(nextHandler, errorHandler, completionHandler);
  • 50. Quick Recap on Observable subscribe() returns a subscription, on which a consumer can call unsubscribe() to cancel the subscription and tear down the producer let sub = observable.subscribe(nextHandler, errorHandler, completionHandler); sub.unsubscribe();
  • 51. What are “operators”? They’re methods on Observable that allow you to compose new observables.
  • 52. How operators work let result = source.myOperator(); result is an Observable, that when subscribed to, subscribes to source, then tranforms it’s values in some way and emits them.
  • 53. How operators work subscription.unsubscribe(); when unsubscribe() is called on that subscription, the unsubscription logic from both result and source are called.
  • 54. How operators work • Operators pass each value from one operator to the next, before proceeding to the next value in the set.* • This is different from array operators (think map and filter) which will process the entire array at each step. • *This can be changed with Schedulers.
  • 57. simple operators • map() • filter() • reduce() • first() • last() • single() • elementAt() • toArray() • isEmpty() • take() • skip() • startWith() • and many more…
  • 58. merging and joining operators • merge • mergeMap (flatMap) • concat • concatMap • switch • switchMap • combineLatest • withLatestFrom • zip • forkJoin • expand
  • 59. splitting and grouping operators • groupBy • window • partition
  • 60. buffering strategy operators • buffer • throttle • debounce • sample
  • 61. With ES7 function bind, you can roll your own* (*coming soon to TypeScript?)
  • 62. “hot” vs “cold” observables • Observables are “cold” by default • “Cold” observables create a new producer each time a consumer subscribes to them • “Hot” observables share a single producer with every consumer that subscribes to them.
  • 63. Multiplexed WebSocket • Connect to a web socket server • For each data stream • send a subscription message to the server • filter out responses from the server • when done, send an unsubscription message. • Ideally, the socket is only open while you require data from it.
  • 64. Multiplexed WebSocket • RECONNECTION?! • maintain a state of all of the multiplexed data streams your views need. • check to see when you’re able to reconnect • reconnect the socket • once the socket is reopened, send all of the subscription messages again
  • 65. Create an Observable that wraps a WebSocket
  • 66. It will create the WebSocket when you subscribe()
  • 67. It emits messages events that arrive on the WebSocket
  • 68. And when it unsubscribes, it will tear down the WebSocket!
  • 69. “Share” to make it “hot”… We don’t want each subscription creating it’s own websocket.
  • 70. Create an Observable that wraps our Socket Observable
  • 71. filter the messages from the Socket Observable to what you need and subscribe
  • 72. Send a message to the server to start getting the data over the socket
  • 73. on unsubscribe, tell the server to stop sending data and unsubscribe from the socket observable
  • 74. Add a retryWhen to retry the whole thing if something goes wrong with the multiplexed observable
  • 75. “share” the observable to make it “hot”, so many consumers can share this producer.
  • 77. Never trust anyone with only good things to say about their library/framework.
  • 78. What’s bad in RxJS? • “Zalgo”.. don’t use mutable outer scoped variables in your operators or subscriptions! • Unbounded buffers! The zip operator in particular is dangerous here. • Too many operators to remember.
  • 79. Twitter: @benlesh github: blesh ben@benlesh.com GOOD: Comments. BETTER: Questions. BEST: Corrections! Thank you!

Editor's Notes

  1. Luis Gabriel Adrian Omelo Jinroh Rob Wormwald