Successfully reported this slideshow.
Your SlideShare is downloading. ×

Angular2 rxjs

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
Rxjs vienna
Rxjs vienna
Loading in …3
×

Check these out next

1 of 69 Ad

More Related Content

Slideshows for you (20)

Viewers also liked (20)

Advertisement

Similar to Angular2 rxjs (20)

Advertisement

Recently uploaded (20)

Angular2 rxjs

  1. 1. Rxjs for angular 2 christoffer noring google developer expert
  2. 2. In the beginning There was callback hell Unreadable
  3. 3. Angular 1 and promises We got more ordered code with constructs like get() .then( doSomething ) .then( somethingElse ) .then( lastAction ) .catch( catchAll ) No callback hell anymore :) We could do stuff like first do A then based on As result do B
  4. 4. $q.when( data ) function doSomethingAsync(){ var deferred = $q.defer(); setTimeout( () => { if(someCondition) { deferred.resolve( data ) } else { deferred.reject( err ); } },3000 ) return deferred.promise; } OR We could wrap up async code in a nice way doSomethingAsync().then((data) => { console.log(data); }, (err) => { console.log(err); }) Use this one1 2
  5. 5. function doAsync(){ new Promise( (resolve, reject) => { setTimeout({ resolve(data); },3000); }) } doAsync() .then((data) => { }, err => { }) Or we could use native promises Promise.all( get(), getMore().. )
  6. 6. Everything was great or?
  7. 7. Issues with promises Not cancellable We need to write a lot of code to retry our logic, becomes messy Only returns one value Not easy to compose with other things like callbacks and event etc, although them being async in their nature Cumbersome to retry
  8. 8. A better way, observables stream of values over time 1 2 3 4 5 time 6
  9. 9. Enter observables var stream = new Rx.Observable.create( fnSuccess, fnError, fnCompleted ) stream.subscribe((data) => { console.log( “Data”,data ); }) nothing happens till someone subscribes
  10. 10. Observable with error var stream = Rx.Observable.create(function(observer){ observer.onNext(1); observer.onNext(2); observer.onNext(3); observer.onError( ‘there is an error’ ) }) stream.subscribe( function(data){ console.log( data ); }, function(error) { console.error( error ); } )
  11. 11. var stream = Rx.Observable.create(function(observer){ observer.onNext( 1 ); observer.onNext( 2 ); observer.onNext( 3 ); observer.onCompleted(); }) stream.subscribe( function(data){ console.log( data ); }, function(error){ console.error( error ); }, function(){ console.info( “completed” ); } ) Observable with completion
  12. 12. var homemadeStream = Rx.Observable.create((observer) => { var i=0; var handle = setInterval(function() { observer.onNext( i++ ); }, 500); return function(){ console.log('Disposing timeout'); clearTimeout( handle ); } }); Observable with cancellation var subscription2 = homemadeStream.subscribe((val) => { console.log('Homemade val',val); }); setTimeout(function() { console.log('Cancelling homemadeStream'); subscription2.dispose(); }, 1500); we clean up no more values are emitted .unsubscribe()
  13. 13. Wrapping something into an observer var stream = Rx.Observable.create(function(observer){ var request = new XMLHttpRequest(); request.open( ‘GET’, ‘url’ ); request.onload = function(){ if(request.status === 200) { observer.onNext( request.response ); observer.onCompleted(); } else { observer.onError( new Error( request.statusText ) ) } } request.onerror = function(){ observer.onError( new Error(‘unknown error’) ); } request.send(); }) 1 2 3 3 stream.subscribe( (result) => { console.log( resu err => {} () => {}) 1 3 2
  14. 14. Everything is a stream
  15. 15. You an combine async concepts click events user inputs data from server callbacks socket
  16. 16. You can create observable by hand but is more likely to create them from something
  17. 17. Different ways to create an observable Rx.Observable.fromArray([ 1,2,3,4 ]) Rx.Observable.fromEvent(element, ‘event’); Rx.Observable.fromArray(eventEmitter, ‘data’, function(){}) Rx.Observable.fromNodeCallback(fs.createFile) Rx.Observable.fromCallback(obj.callback) Rx.Observable.range(1,3) Rx.Observable.interval(miliseconds)
  18. 18. Operators gives observable their power
  19. 19. var stream = Rx.Observable .interval(500) .take(5) .filter((val) = > { return val % 2 === 0; }) .map((val) => { return “val” + 1; }) Operators stream.subscribe(() => { }) operator is a function that returns an observable emit value every 500 ms limit number of values operator: change the value operator: only emit certain values
  20. 20. Wait, it looks like loadash?
  21. 21. Comparison list .map( x = > x.prop ) .filter( x => x > 2 ) .take( 2 ) list .map( x = > x.prop ) .filter( x => x > 2 ) .take( 2 ) .subscribe( x => console.log(x), ) service.get() .then( x => console.log(x) ) ) Array like, handles async but can also - Cancelled - Retried lodash/array functions async observable
  22. 22. Operators overview 120+ operators ( 60+ Rxjs5 ) Combination Conditional Creational Error handling Filtering Transformation Utility Categories
  23. 23. How am I gonna keep track of all that? Use the most common ones, and then expand your knowledge Look at marble diagrams which one you need Also create your own to help you in the coding process
  24. 24. Stream Other stream Resulting stream 1 Most operators are covered at rxmarbles.com 2 3 4 5 1 2 3 4 5 Marble diagrams stream/s + operation = new stream operation by the operator
  25. 25. Start with these operators map filter flatMap switchMap do merge of interval take
  26. 26. of Rx.Observable .of(1,2,3,4) .subscribe((val) => { console.log( val ) }) Emits exactly whats in there Good for prototyping an idea
  27. 27. map Rx.Observable .of(1,2,3) .map((val) => { return “” + val; }) Point is to take each value, change it and return a new value in its place
  28. 28. filter Rx.Observable .of(1,2,3) .filter((val) => { return val % 2 === 0; }) . Point is to reduce the number of values
  29. 29. flatMap Rx.Observable .of(1,2,3) .map( (val) => { } ) return Rx.DOM.getJSON( ‘data’ + val +‘.json' ) Becomes a list of observables, hard to work with Rx.Observable .of(1,2,3) .flatMap( (val) => { } ) return Rx.DOM.getJSON( ‘data’ + val +‘.json' ) Flatten all observables to a meta stream
  30. 30. flatMap - example 2, auto complete flatmapExample = Rx.Observable.fromEvent(input,'keyup') .map( function(ev){ return ev.target.value; }) .filter(function(text){ return text.length >=3; }) .distinctUntilChanged() .flatMap( function(val){ return Rx.DOM.getJSON( 'data3.json' ); }) flatmapExample.subscribe( function(result){ console.log('Flatmap', result); }) Transform event to char Wait until we have 3 chars Only perform search if this ‘search’ is unique
  31. 31. flatMap pe of streams and wants it to become something completely else like a strea clicks ajax persons Also avoid this ajax clicks ajax ajax Subscribe Subscribe Subscribe Instead become ajax clicks ajax ajax ajax personsflat map map one subscribe
  32. 32. switchMap Switch map, complete something based on a condition breakCondition = Rx.Observable.fromEvent(document,'click'); breakCondition.switchMap( function(val){ return Rx.Observable.interval(3000).mapTo('Do this if nothing breaks me }) breakCondition.subscribe( function(val){ console.log('Switch map', val); })
  33. 33. do var stream = Rx.Observable.of(1,2,3,4,5); var subscription = stream .do(function(val){ console.log('Current val', val); }) .filter(function(val){ return val % 2 === 0; }); subscription.subscribe(function(val){ console.log('Val',val); }) Echos every value without changing it, used for logging
  34. 34. concat/merge concat merge var concat = Rx.Observable.concat( stream, stream2 ); var stream = Rx.Observable.fromArray([1,2,3,4]); var stream2 = Rx.Observable.fromArray([5,6,7,8]); 1, 2, 3, 4, 5, 6, 7 ,8 var merge = Rx.Observable.merge( stream, stream2 ); 1, 5, 2, 6, 3, 7, 4 ,8 first stream emits all values then remaining value Needs queue Scheduler in Rxjs5
  35. 35. Other useful operators
  36. 36. Delay, the whole sequence stream .delay(1000) .subscribe( (val) => { var newTime = new Date().getTime(); console.log('Delayed', val + " " + (newTime - time)); }) Rx.Observable.merge( Rx.Observable.of('Marco').delay(1000), Rx.Observable.of('Polo').delay(2000) ).subscribe((val) => { var newTime = new Date().getTime(); console.log('Merged Delay', val + " " + (newTime - time)); }) Delay ….. 1 second 1 2 3 ….. 1 second Marco ….. 2 second Polo
  37. 37. Debounce var debounceTime = Rx.Observable .fromEvent(button,'click') .debounce(2000); debounceTime.subscribe( function(){ console.log('mouse pressed'); }) Ignores all generated mouse click events for 2 seconds click click click click click ignore ignore ignore ignore use …. 2 seconds passed
  38. 38. Fetching data with fetch api and promise fetch(‘data.json',init) .then(function(response) { return response.blob(); }) var init = { method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' }; There is always this one if you don’t want to use Observables
  39. 39. Angular 2 and rxjs router, most actions are observables http lib is observables What about angular 2 and rxjs, how is it used?
  40. 40. Fetching data with Observable getAll() { return http.get(`${baseUrl}`/people, {}) .map( mapPeople ) } getAll().subscribe((people) => { console.log(‘people’, people); }) .catch((err) => { console.log(‘Error’, err); }) mapPeople(response:Response) { return response.json().results.map(toPerson) } fetch data, map result, handle error
  41. 41. Fetch data Observable cancelling var stream = getAll() { return http.get(`${baseUrl}`/people, {}) .map( mapPeople ) } setTimeout(() => { stream.dispose(); },3000); stream.subscribe((data) => { }) unsubscribe() in rxjs5 BUT we can cancel!!
  42. 42. Fetch data Observable retry var stream = Rx.DOM.get('/products.json').retry(5); stream.subscribe((val) => { console.log('Data', val); }, err => console.log(err)); 5 failed attempts then we hit error callback Its so easy to retry, imagine how messy this code would be with a promise
  43. 43. Subject Observer Observable Subject Inherits from both the subject can act as a proxy for a group of subsc
  44. 44. var subject = new Rx.Subject(); subject.subscribe((val) => { console.log( 'Produced by subject', val ); }); subject.onNext(1); subject.onCompleted(); Acts like an observer Acts like an observable Subject
  45. 45. var subject = new Rx.Subject(); var source = Rx.Observable.interval(500); source.subscribe(subject); subject.subscribe( (val) => { console.log('Sub', val); }, (err) => console.log(err), () => console.log('completed') ); setTimeout(function() { subject.onCompleted(); }, 3000); Pass subject as an observer Receives all the values pushed out by the source Able to stop receiving values Subject
  46. 46. var subject = new Rx.Subject(); var source = Rx.Observable.interval(500).take(3); source.subscribe( subject ); subject.subscribe((val) => { console.log('Subject', val); }); subject.onNext('Mess1'); subject.onNext('Mess2'); setTimeout(function() { subject.onCompleted(); }, 1600); Listens to all values from source Add to stream Order important Subject onNext() before subscribe is lost
  47. 47. var subject = Rx.ReplaySubject(); subject.onNext(1); subject.subscribe((val) = > { console.log('Replay', val); }) subject.onNext(2); subject.onNext(3); var subject = Rx.Subject(); subject.onNext(1); subject.subscribe((val) = > { console.log('Replay', val); }) subject.onNext(2); subject.onNext(3); Normal subject, everything before subscribe is lost Replay subject, nothing is lost Subject - types
  48. 48. BehaviourSubject Good for default values /* Initialize with initial value of 42 */ var subject = new Rx.BehaviorSubject(42); var subscription = subject.subscribe( function (x) { console.log('Next: ' + x.toString()); }, function (err) { console.log('Error: ' + err); }, function () { console.log('Completed'); }); subject.onNext(56); subject.onCompleted(); // => Completed Init/Default value Next: 42 Next: 56
  49. 49. Angular 2 with rxjs Rxjs is a big library, if you just have request/reponse then do import 'rxjs/add/operator/map'; One import per used operator import * as Rx from 'rxjs/Rx'; imports the whole of Rxjs !!!, GOOD for development BAD for production Then carry on coding 1 1a
  50. 50. Component to Component You want something that can produce value, that you can listen to this.subject = new Rx.Subject(); function sendData(data){ this.subject.next( data ) } function getSubject(){ return this.subject; } //service impl Component1 Component1 service.getSubject().subscribe(()=>{}) service.sendData( data ) BUT, can be made nicer with a uniform data flow
  51. 51. Angular 2 rxjs setup ngOnInit(){ this.subscription = this.service.getData(); } ngOnDestroy(){ this.subscription.unsubscribe(); } Setup Teardown life cycle hooks
  52. 52. Angular 2 So when to use it? Its a better promise Cancelling Retry Want to combine callbacks, event and data fetch? Less code with rxjs there is a forkJoin operator that replace Promise.all() etc anything you can do, I can do better no you can’t :( Observable Promise
  53. 53. Testing Solution : bending time with schedulers Hard to test right? Some methods might take minutes?
  54. 54. Schedulers bending time
  55. 55. Because scheduler has its own virtual clock Anything scheduled on that scheduler will adhere to time denoted on the clock I.e we can bend time for ex unit testing
  56. 56. var onNext = Rx.ReactiveTest.onNext; var scheduler = new Rx.TestScheduler(); var subject = scheduler.createColdObservable( onNext(100,'first'), onNext(200,'second') ); var result; subject.subscribe((val) => { result = val; }); scheduler.advanceBy( 100 ); console.log('Should equal', result === 'first'); scheduler.advanceBy( 100 ); console.log('Should equal', result === 'second'); Advance time Assert Advance time Assert create observable from scheduler emit values
  57. 57. var testScheduler = new Rx.TestScheduler(); var stream = Rx.Observable.interval(1000, testScheduler) .take(5) .map((val) => { return val + 1 }) .filter((i) => { return i % 2 === 0 }); var result; stream.subscribe((val) => result = val ); console.log('testing function’); testScheduler.advanceBy(1000); testScheduler.advanceBy(1000); testScheduler.advanceBy(1000); console.log('Should equal', result === 2); testScheduler.advanceBy(1000); testScheduler.advanceBy(1000); console.log('Should equal', result === 4); replace default scheduler 0 1 2
  58. 58. Error scenarios Capture error in .subscribe()
  59. 59. Error handling catchvar errStream = Rx.Observable.throw('Error'); var stream = Rx.Observable.create(function(observer){ observer.onNext(1); }) var merged = Rx.Observable .merge( errStream, stream ) merged.subscribe( function(val){ console.log('Val', val); }, function(err){ console.log('Err', err); }, function(){ console.log('completed'); }) Captured here but sequence interrupted, completed NOT reached
  60. 60. Capture error in .subscribe() + completed stream Error handling
  61. 61. Error handling improved catch var errStream = Rx.Observable.throw('Error'); var stream = Rx.Observable.create(function(obs observer.onNext(1); }) var merged = Rx.Observable .merge( errStream, stream ) .catch(function(err){ return Rx.Observable.of(err); }); merged.subscribe( function(val){ console.log('Val', val); }, function(err){ console.log('Err', err); }, function(){ console.log('completed'); }) Captured here but sequence interrupted, completed IS reached stream not processed though can we improve it? stream killed by errStream :(
  62. 62. Wrap error stream before merging with other streams so we don’t kill other valid streams Error handling
  63. 63. Error handling ignoring We need to handle the erroring stream better From var errStream = Rx.Observable .throw('AAA thump..') To var errStream = Rx.Observable .throw('AAA thump..') .catch(function(err){ return Rx.Observable.of(err); }); This will emit all values and the wrapped error
  64. 64. Process all values and errors by wrapping the errors, everything gets processed Error handling
  65. 65. Error - ignoring other scenario var merged = Rx.Observable .merge( errStream2, stream ) merged.subscribe( function(val){ console.log('Val', val); }, function(err){ console.log('Err', err); }, function(){ console.log('completed'); }) 1,1,2 var errStream2 = Rx.Observable .interval(200) .take(3) .select(function(val){ if(val === 0) { return Rx.Observable.throw('Error stream'); } else { return Rx.Observable.of(val); } }) .select(function(observable){ return observable.catch(Rx.Observable.return('Error handled')); }) .selectMany( function(x){ return x; }); wrap catch and rewrite
  66. 66. Set a policy for error handling of streams when merging so successful stream survive Error handling
  67. 67. Error - ignoring other scenario You have several sources and two terminates You want the other normal source to work var errStream = Rx.Observable .throw('AAA thump..'); var errStreamWithFlattenedData = Rx.Observable .interval(500) .take(3) .flatMap( function(val){ if( val === 1 ) { return Rx.Observable.throw('crashing'); } else { return Rx.Observable.return(val); } }) var normalStream = Rx.Observable.return('anything'); var handledErrorStream = Rx.Observable.onErrorResumeNext( errStream, normalStream, errStreamWithFlattenedData ); handledErrorStream.subscribe(function(err){ console.log('error stream ignored', err); }, function(err){ console.log("error stream ignored, error",err); }, function(){ console.log("completion of error stream ignored"); }) Ensure good streams survive in a merge of failing streams, on
  68. 68. Further reading https://xgrommx.github.io/rx-book http://www.learnrxjs.io/ bacon.js
  69. 69. Thank you

×