Top Banner
Rethink Async with RXJS
53

Rethink Async With RXJS

Dec 17, 2014

Download

Technology

Ryan Anklam

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.
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: Rethink Async With RXJS

Rethink Async with RXJS

Page 2: Rethink Async With RXJS

Senior UI Engineer at

About Me

bittersweetryan

[email protected]

Page 3: Rethink Async With RXJS

Before We Begin

Page 4: Rethink Async With RXJS

Before We Begin

Be KIND to those of us with OCD and…

Page 5: Rethink Async With RXJS

Before We Begin

Change those Dropbox icons to B&W!

Page 6: Rethink Async With RXJS

Reactive Programming!

Page 7: Rethink Async With RXJS

Reactive Programming

Java…

Groovy…and JavaScript

At Netflix do a lot of RX…

.NET…

Page 8: Rethink Async With RXJS

We Build This With RXJS

Page 9: Rethink Async With RXJS

Reactive Programming

What if?

The iterator pattern and observer met at a bar, !fell in love, got married, and had a baby?

Page 10: Rethink Async With RXJS

Reactive Programming

Page 11: Rethink Async With RXJS

Reactive Programming

What if?

This baby would allow you to use the same code to !respond to events and asynchronous operations?

Page 12: Rethink Async With RXJS

Meet Observable

Page 13: Rethink Async With RXJS

Observables

What to events and async functions have in common?

Page 14: Rethink Async With RXJS

Observables

As a mouse moves, doesn’t it just emit coordinates?

Tracking Mouse Movements

Page 15: Rethink Async With RXJS

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}

Page 16: Rethink Async With RXJS

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

Page 17: Rethink Async With RXJS

Observables

Observables Everywhere!• Events!• AJAX Requests!• Node Functions!• Arrays!• Promises!• And more….

Page 18: Rethink Async With RXJS

Observables

Why not another Async approach?

• Replayable!• Composable!• Cancellable!• Cache-able!• Shareable!• Can emit multiple value-able

Page 19: Rethink Async With RXJS

Functional Review!(With an RX twist)

Page 20: Rethink Async With RXJS

Functional Review

Map

ReduceFilter

Zip

Page 21: Rethink Async With RXJS

var searchResultsSets = keyups. map( function( key ){ return Observable.getJSON('/search?' + input.value) });

Functional Review

Map - Transforms data

Page 22: Rethink Async With RXJS

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

Page 23: Rethink Async With RXJS

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.

Page 24: Rethink Async With RXJS

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…' } ]

Page 25: Rethink Async With RXJS

Functional Review

Observable Data Streams Are Like Crazy Straws

keyPresses Observable

subscribe

throttlefilter

mapdistinctUntilChanged

reduce

Page 26: Rethink Async With RXJS

Thinking Functionally

Page 27: Rethink Async With RXJS

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 ); } });

Page 28: Rethink Async With RXJS

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 })

Page 29: Rethink Async With RXJS

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 } });

Page 30: Rethink Async With RXJS

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 });

Page 31: Rethink Async With RXJS

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.

Page 32: Rethink Async With RXJS

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.

Page 33: Rethink Async With RXJS

Flattening Patterns!managing concurrency!

Page 34: Rethink Async With RXJS

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

Page 35: Rethink Async With RXJS

Observables = Events Over Time

1s 2s 3s 4s 5s 6s

BR

BRE

BREAK

BREAKJ

BREAKING

BREAKING BA

BREAKING BAD

Ajax requests over time…

Page 36: Rethink Async With RXJS

The Three Musketeers

Goofy as merge

Donald as concat

Mickey as switchLatest

Starring

Page 37: Rethink Async With RXJS

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

Page 38: Rethink Async With RXJS

Merge

1s 2shttp://jsbin.com/wehusi/13/edit

data

data

data

data

Page 39: Rethink Async With RXJS

Concat

1s 2shttp://jsbin.com/fejod/4/edit

!

!

data

data

data

data

Page 40: Rethink Async With RXJS

SwitchLatest

!

1s 2s

data

data

data

data

Page 41: Rethink Async With RXJS

Building Animated AutoComplete!

Putting Everything Together

Page 42: Rethink Async With RXJS

Animated Autocomplete

SearchBBrBreaking Bad Bridezillas Brothers & Sisters The Breakfast Club Brother Bear

Breaking Bad The Breakfast Club Breakout Kings Breaking Dawn Breaking Amish

BreBreaBreak

Page 43: Rethink Async With RXJS

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

Page 44: Rethink Async With RXJS

var keyups = Observable. fromEvent( searchInput, 'keypress');

Animated Autocomplete

Page 45: Rethink Async With RXJS

var searchResultsSets = keyups. filter( function ( e ){ return input.value.length > 1; }). map( function( e ){ return Observable. getJSON('/search?' + input.value); }). switchLatest();

Animated Autocomplete

Page 46: Rethink Async With RXJS

var animateOuts = keyups. map(function( resultSet ){ return animateOut(resultsDiv); }); !var animateIns = searchResultsSets. map( function( resultSet ){ return Observable. of(resultsSet). concat(animateIn(resultsDiv)); });

Animated Autocomplete

Page 47: Rethink Async With RXJS

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

Page 48: Rethink Async With RXJS

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

Page 49: Rethink Async With RXJS

In Conclusion!!

[email protected]@bittersweetryan!

Page 50: Rethink Async With RXJS

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

Page 51: Rethink Async With RXJS

To Find Out More

• http://github.com/jhusain/learnrx!• https://github.com/Reactive-Extensions/RxJS/tree/master/doc!• Chat with me

Page 52: Rethink Async With RXJS

Questions?!

Page 53: Rethink Async With RXJS

Thank You.!!

[email protected]@bittersweetryan!