Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Rethink Async with
RXJS
Senior UI Engineer at
About Me
bittersweetryan
ranklam@netflix.com
Before We Begin
Before We Begin
Be KIND to those of us with OCD and…
Before We Begin
Change those Dropbox icons to B&W!
Reactive
Programming!
Reactive Programming
Java…
Groovy…
and JavaScript
At Netflix do a lot of RX…
.NET…
We Build This With RXJS
Reactive Programming
What if?
The iterator pattern and observer met at a bar, !
fell in love, got married, and had a baby?
Reactive Programming
Reactive Programming
What if?
This baby would allow you to use the same code to !
respond to events and asynchronous opera...
Meet Observable
Observables
What to events and async functions have in common?
Observables
As a mouse moves, doesn’t it just emit coordinates?
Tracking Mouse Movements
Observables
Tracking Mouse Movements
1s 2s
Mousedown
0s
Mouseup
{x : 200, y: 521} {x : 240, y: 552} {x : 210, y: 602} {x :...
Observables
var mouseMoves =
Observable.fromEvent( mouseDown )
.takeUntil( mouseUp )
.map( function( mouseEvent ){
return ...
Observables
Observables Everywhere!
• Events!
• AJAX Requests!
• Node Functions!
• Arrays!
• Promises!
• And more….
Observables
Why not another Async approach?
• Replayable!
• Composable!
• Cancellable!
• Cache-able!
• Shareable!
• Can em...
Functional Review!
(With an RX twist)
Functional Review
Map
Reduce
Filter
Zip
var searchResultsSets =
keyups.
map( function( key ){
return Observable.getJSON('/search?' +
input.value)
});
Functional R...
var searchResultsSets = keyups.
filter( function ( key ){
return input.value.length > 1;
}).
map( function( key ){
return ...
var html =
searchResultsSets.
reduce(function( prev,curr ) {
return prev + '<li>' + curr.name + '</li>';
},'' );
Functiona...
Functional Review
Zip - Combines two collections
var movies = [ 'Super Troopers', 'Pulp Fiction',
'Fargo' ] ;
var boxArts ...
Functional Review
Observable Data Streams Are Like Crazy Straws
keyPresses Observable
subscribe
throttle
filter
map
distinc...
Thinking Functionally
Thinking Functionally
Replace loops with map.
searchResults = Observable.
getJSON(‘/people?’ + input.value);
!
searchResul...
Thinking Functionally
Replace loops with map and reduce.
searchResults = Observable.
getJSON(‘/people?’ + input.value).
ma...
Thinking Functionally
Replace if’s with filters.
var keyPresses = O.fromEvent( el, 'keyup' )
!
keyPresses.forEach( function...
Thinking Functionally
Replace if’s with filters.
var enterPresses = O.fromEvent( el, 'keyup' )
.filter( function( e ){
retu...
Thinking Functionally
Don’t put too much in a single stream.
var submits = O.fromEvent(input,'keypresses').
throttle().
ma...
Thinking Functionally
var keys =
Observable.fromEvent(input,'keypresses').
throttle().
map( function( e ){
return e.which
...
Flattening Patterns!
managing concurrency!
Observables = Events Over Time
Key presses over time…
.5s 1s 1.5s 2s 2.5s 3s
B R E A K IJ <- N G B A D
Observables = Events Over Time
1s 2s 3s 4s 5s 6s
BR
BRE
BREAK
BREAKJ
BREAKING
BREAKING BA
BREAKING BAD
Ajax requests over ...
The Three Musketeers
Goofy as merge
Donald as concat
Mickey as switchLatest
Starring
Flattening Patterns
merge - combines items in a collection as each item arrives
concat - combines collections in the order...
Merge
1s 2s
http://jsbin.com/wehusi/13/edit
data
data
data
data
Concat
1s 2s
http://jsbin.com/fejod/4/edit
!
!
data
data
data
data
SwitchLatest
!
1s 2s
data
data
data
data
Building Animated
AutoComplete!
Putting Everything Together
Animated Autocomplete
SearchBBrBreBreaBreak
Observables = Events Over Time
Simple Widget, High Complexity
• Respond to key presses
• Send off Ajax requests
• Animate ...
var keyups =
Observable.
fromEvent( searchInput, 'keypress');
Animated Autocomplete
var searchResultsSets =
keyups.
filter( function ( e ){
return input.value.length > 1;
}).
map( function( e ){
return Obse...
var animateOuts =
keyups.
map(function( resultSet ){
return animateOut(resultsDiv);
});
!
var animateIns =
searchResultsSe...
var resultSets =
animateOuts.
merge(animateIns).
concatAll();
!
resultSets.

forEach( function( resultSet ){
if (resultSet...
var keyups =
Observable.
fromEvent( searchInput, ‘keypress');
!var searchResultsSets =
keyups.
filter( function ( e ){
ret...
In Conclusion!
!
ranklam@netflix.com

@bittersweetryan!
In Conclusion
• Observables are a POWERFUL abstraction!
• Requires a bit of mental rewiring!
• The RX API is HUGE, take ba...
To Find Out More
• http://github.com/jhusain/learnrx!
• https://github.com/Reactive-Extensions/RxJS/tree/master/doc!
• Cha...
Questions?!
Thank You.!
!
ranklam@netflix.com

@bittersweetryan!
Upcoming SlideShare
Loading in …5
×

Rethink Async With RXJS

20,545 views

Published on

This is an updated version of my "Add more fun to your functional programming with RXJS". It includes a bit more background information on Reactive programming.

Published in: Technology

Rethink Async With RXJS

  1. 1. Rethink Async with RXJS
  2. 2. Senior UI Engineer at About Me bittersweetryan ranklam@netflix.com
  3. 3. Before We Begin
  4. 4. Before We Begin Be KIND to those of us with OCD and…
  5. 5. Before We Begin Change those Dropbox icons to B&W!
  6. 6. Reactive Programming!
  7. 7. Reactive Programming Java… Groovy… and JavaScript At Netflix do a lot of RX… .NET…
  8. 8. We Build This With RXJS
  9. 9. Reactive Programming What if? The iterator pattern and observer met at a bar, ! fell in love, got married, and had a baby?
  10. 10. Reactive Programming
  11. 11. Reactive Programming What if? This baby would allow you to use the same code to ! respond to events and asynchronous operations?
  12. 12. Meet Observable
  13. 13. Observables What to events and async functions have in common?
  14. 14. Observables As a mouse moves, doesn’t it just emit coordinates? Tracking Mouse Movements
  15. 15. Observables Tracking Mouse Movements 1s 2s Mousedown 0s Mouseup {x : 200, y: 521} {x : 240, y: 552} {x : 210, y: 602} {x : 199, y: 579} {x : 221, y: 530} {x : 218, y: 570} {x : 200, y: 599}
  16. 16. Observables var mouseMoves = Observable.fromEvent( mouseDown ) .takeUntil( mouseUp ) .map( function( mouseEvent ){ return { x : mouseEvent.clientX, y : mouseEvent.clientY }; } ) ; ! mouseMoves.subscribe( function( cords ){ //do stuff for each mouse move cord }); Mouse Moves Observable
  17. 17. Observables Observables Everywhere! • Events! • AJAX Requests! • Node Functions! • Arrays! • Promises! • And more….
  18. 18. Observables Why not another Async approach? • Replayable! • Composable! • Cancellable! • Cache-able! • Shareable! • Can emit multiple value-able
  19. 19. Functional Review! (With an RX twist)
  20. 20. Functional Review Map Reduce Filter Zip
  21. 21. var searchResultsSets = keyups. map( function( key ){ return Observable.getJSON('/search?' + input.value) }); Functional Review Map - Transforms data
  22. 22. var searchResultsSets = keyups. filter( function ( key ){ return input.value.length > 1; }). map( function( key ){ return Observable.getJSON('/search?' + input.value) ); Functional Review Filter - Narrows Collections
  23. 23. var html = searchResultsSets. reduce(function( prev,curr ) { return prev + '<li>' + curr.name + '</li>'; },'' ); Functional Review Reduce - Turns a collection into a single value Initial prev value.
  24. 24. Functional Review Zip - Combines two collections var movies = [ 'Super Troopers', 'Pulp Fiction', 'Fargo' ] ; var boxArts =[ '/cdn/23212/120x80', '/cdn/73212/120x80','/cdn/99212/120x80' ] ; ! var withArt = Observable. zip(movies, boxarts, function(movie, boxart){ return {title : movie, boxart : boxart}; }); ! //[{title : 'Super Troo…', boxart : '/cdn…'}, // {title : 'Pulp Fict…', boxart : '/cdn…' }, // {title : 'Fargo', boxart : 'cdn…' } ]
  25. 25. Functional Review Observable Data Streams Are Like Crazy Straws keyPresses Observable subscribe throttle filter map distinctUntilChanged reduce
  26. 26. Thinking Functionally
  27. 27. Thinking Functionally Replace loops with map. searchResults = Observable. getJSON(‘/people?’ + input.value); ! searchResults. forEach( function( reps ){ var names = []; for( var i = 1; i < resp; i++ ){ var name = data[i].fName + ' ' + data[i].lName; names.push( name ); } });
  28. 28. Thinking Functionally Replace loops with map and reduce. searchResults = Observable. getJSON(‘/people?’ + input.value). map( function( data ){ return data.fName + data.lName; } ); ! searchResults.forEach( function( resp ){ //resp will now be the names array })
  29. 29. Thinking Functionally Replace if’s with filters. var keyPresses = O.fromEvent( el, 'keyup' ) ! keyPresses.forEach( function( e ){ if( e.which === keys.enter ){ //=> no! //do something } });
  30. 30. Thinking Functionally Replace if’s with filters. var enterPresses = O.fromEvent( el, 'keyup' ) .filter( function( e ){ return e.which && e.which === keys.enter; }); ! enterPresses.forEach( function( e ){ //do something });
  31. 31. Thinking Functionally Don’t put too much in a single stream. var submits = O.fromEvent(input,'keypresses'). throttle(). map( function( e ){ return e.which } ). filter( function( key ){ return key === keys.enter || keys.escape; }). map(). reduce(). ... Smaller streams are OK.
  32. 32. Thinking Functionally var keys = Observable.fromEvent(input,'keypresses'). throttle(). map( function( e ){ return e.which } ); ! var enters = keys.filter( function( key ) ){ return e.which === keys.enter; } ! var escapes = keys.filter( function( key ) ){ Don’t put too much in a single stream. Smaller streams are OK.
  33. 33. Flattening Patterns! managing concurrency!
  34. 34. Observables = Events Over Time Key presses over time… .5s 1s 1.5s 2s 2.5s 3s B R E A K IJ <- N G B A D
  35. 35. Observables = Events Over Time 1s 2s 3s 4s 5s 6s BR BRE BREAK BREAKJ BREAKING BREAKING BA BREAKING BAD Ajax requests over time…
  36. 36. The Three Musketeers Goofy as merge Donald as concat Mickey as switchLatest Starring
  37. 37. Flattening Patterns merge - combines items in a collection as each item arrives concat - combines collections in the order they arrived switchLatest - switches to the latest collection that ! arrives
  38. 38. Merge 1s 2s http://jsbin.com/wehusi/13/edit data data data data
  39. 39. Concat 1s 2s http://jsbin.com/fejod/4/edit ! ! data data data data
  40. 40. SwitchLatest ! 1s 2s data data data data
  41. 41. Building Animated AutoComplete! Putting Everything Together
  42. 42. Animated Autocomplete SearchBBrBreBreaBreak
  43. 43. Observables = Events Over Time Simple Widget, High Complexity • Respond to key presses • Send off Ajax requests • Animate out when search results become invalid • Animate in when new search results come in • Don’t show old results • Make sure one animation is finished before starting 
 another
  44. 44. var keyups = Observable. fromEvent( searchInput, 'keypress'); Animated Autocomplete
  45. 45. var searchResultsSets = keyups. filter( function ( e ){ return input.value.length > 1; }). map( function( e ){ return Observable. getJSON('/search?' + input.value); }). switchLatest(); Animated Autocomplete
  46. 46. var animateOuts = keyups. map(function( resultSet ){ return animateOut(resultsDiv); }); ! var animateIns = searchResultsSets. map( function( resultSet ){ return Observable. of(resultsSet). concat(animateIn(resultsDiv)); }); Animated Autocomplete
  47. 47. var resultSets = animateOuts. merge(animateIns). concatAll(); ! resultSets.
 forEach( function( resultSet ){ if (resultSet.length === 0) { $('.search-results').addClass('hidden'); } else { resultsDiv.innerHTML = toHTML(resultSet ); } } ); Animated Autocomplete
  48. 48. var keyups = Observable. fromEvent( searchInput, ‘keypress'); !var searchResultsSets = keyups. filter( function ( e ){ return input.value.length > 1; }). map( function( e ){ return Observable. getJSON('/search?' + input.value); }). switchLatest(); var animateOuts = keyups. map(function( resultSet ){ return animateOut(resultsDiv); }); !var animateIns = searchResultsSets. map( function( resultSet ){ return Observable. of(resultsSet). concat(animateIn(resultsDiv)); }); !var resultSets = animateOuts. merge(animateIns). concatAll(); !resultSets.
 forEach( function( resultSet ){ if (resultSet.length === 0) { $('.search-results').addClass('hidden'); } else { resultsDiv.innerHTML = toHTML(resultSet ); } } ); Animated Autocomplete
  49. 49. In Conclusion! ! ranklam@netflix.com
 @bittersweetryan!
  50. 50. In Conclusion • Observables are a POWERFUL abstraction! • Requires a bit of mental rewiring! • The RX API is HUGE, take baby steps! • Merging strategies are the key coordinating async! • Compose streams of data from small streams
  51. 51. To Find Out More • http://github.com/jhusain/learnrx! • https://github.com/Reactive-Extensions/RxJS/tree/master/doc! • Chat with me
  52. 52. Questions?!
  53. 53. Thank You.! ! ranklam@netflix.com
 @bittersweetryan!

×