Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

RxJS - The Reactive extensions for JavaScript

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Wird geladen in …3
×

Hier ansehen

1 von 77 Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Andere mochten auch (20)

Anzeige

Ähnlich wie RxJS - The Reactive extensions for JavaScript (20)

Aktuellste (20)

Anzeige

RxJS - The Reactive extensions for JavaScript

  1. 1. RxJS Reactive extensions for JavaScript
  2. 2. $ whoami Viliam Elischer SW Engineer at ZOOM International twitter.com/vireliam github.com/vire
  3. 3. Introduction Theory Building blocks Usage Alternatives Resources Agenda
  4. 4. History Originally project Volta (December 2007) Erik Meijer: Volta is an experiment that enables Microsoft to explore new ways of developing distributed applications. Today ReactiveX supports RxJava, RxJS, Rx.NET, UniRx, RxScala, RxClojure, RxCpp, Rx.rb, RxPY, RxGroovy, RxJRuby, RxKotlin, RxSwift, RxNetty, RxAndroid RxCocoa Mental fathers: Erik Meijer, Matthew Podwysowski RxJS Contributors: Ben Lesh, Paul Daniels + 164 more individuals
  5. 5. RxJS is set of libraries for composing asynchronous and event-based programs.
  6. 6. Developers represent asynchronous data streams with Observables, query asynchronous data streams using many operators, and parameterize the concurrency in the asynchronous data streams using Schedulers.
  7. 7. Developers represent asynchronous data streams with Observables, query asynchronous data streams using many operators, and parameterize the concurrency in the asynchronous data streams using Schedulers.
  8. 8. Developers represent asynchronous data streams with Observables, query asynchronous data streams using many operators, and parameterize the concurrency in the asynchronous data streams using Schedulers.
  9. 9. Asynchronous data streams demystified
  10. 10. A Stream is just a fancy word for a sequence of “things” streamed over time.
  11. 11. A sequence is infinite until it completes. It is not possible to add anything after completion.
  12. 12. The act of change on a sequence is simply an event.
  13. 13. A Stream is an infinite sequence of events over time.
  14. 14. A Sequence can be observed and acts as a Subject of observation.
  15. 15. An Observable sequence.
  16. 16. The ability to observe was defined because there is a good reason or interest.
  17. 17. An Observer is interested in what happens with the Subject (Observable).
  18. 18. To get notified about changes an Observer must subscribe to an Observable sequence.
  19. 19. A Subscription represents the contract between Observer and Observable.
  20. 20. The Subject notifies the Observer about changes by pushing events.
  21. 21. The Observer represents behavior for handling events pushed by the observed sequence.
  22. 22. Such prepared reaction to a push happens asynchronously.
  23. 23. Leveraging Observables from managing the “when” aspect is possible thanks to Schedulers.
  24. 24. Most important features of Observables are fully empowered when sophisticated operations are being performed in form of queries.
  25. 25. Computation scenarios time / val One value Multiple values Synchronous | Pull Object Iterables Array | Map | Set | Object Asynchronous | Push Promise Observables
  26. 26. Design patterns
  27. 27. Faig Ahmed - Liquid, Handmade Woolen carpet 200x290, year 2014
  28. 28. GOF Design Patterns Iterator IEnumerable<T> and IEnumerator<T> interactive computations where the consumer synchronously pulls data from the producer Observer IObservable<T> and IObserver<T> reactive computations where the producer asynchronously pushes data to the consumer http://csl.stanford.edu/~christos/pldi2010.fit/meijer.duality.pdf http://josemigueltorres.net/index.php/ienumerableiobservable-duality/
  29. 29. Asynchronously? Sure, we have promises...
  30. 30. Problematic aspects of promises Error swallow Bulk processing (map 20 XHRs to 1 result) Cancellation (context switching) Replay of previous values
  31. 31. Building blocks function Disposable() { } Disposable.prototype.dispose = () => { ... } function Observable() { } Observable.prototype.subscribe = observer => { ... } function Observer() { } Observer.prototype.onNext = value => { ... }; Observer.prototype.onError = error => { ... }; Observer.prototype.onCompleted = () => { ... };
  32. 32. RxJS = Observables + Operators + Schedulers.
  33. 33. It’s all about operators...
  34. 34. Operator, I need an operator.
  35. 35. We do have operators
  36. 36. 131
  37. 37. creation, conversion, combine, functional, mathematical, time, exceptions, miscellaneous, selection and primitives
  38. 38. Creation - Observable.just | .return Rx.Observable.just(42) .subscribe(val => {console.log('val: ' + val)}) // val: 42
  39. 39. Creation - Observable.create const source = Rx.Observable.create(observer => { observer.onNext(42); observer.onError(new Error('ha-ha!')); observer.onCompleted(); }); source.subscribe( val => console.log('onNext:', val), error => console.log('onError:', error), () => console.log('onCompleted:') );
  40. 40. Creation - Observable.create + Disposable const source = Rx.Observable.create(observer => { observer.onNext(42); observer.onError(new Error('ha-ha!')); observer.onCompleted(); return Rx.Disposable.create(() => console.log('disposed')); }); source.subscribe( val => console.log('onNext:', val), error => console.log('onError:', error), () => console.log('onCompleted:') );
  41. 41. Creation - Observable.create + Disposable const asyncOp = () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('resolving!') resolve(42); }, 1000); console.log('promise in progress...') }); } asyncOp().then(val => console.log('resolved with: ', val))
  42. 42. Promises can’t be disposed!
  43. 43. const asyncOp = () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('resolving!') resolve(42); }, 1000); console.log('promise in progress...') }); } asyncOp().then(val => console.log('resolved', val)) const source = Rx.Observable.create(observer => { console.log('Observable in progress') const timeout = setTimeout(() => { observer.onNext('onNext after two seconds!'); }, 2000); return Rx.Disposable.create(() => { console.log('disposed'); clearTimeout(timeout); }); }); const subscription = source.subscribe( val => console.log('onNext:', val), ); setTimeout(() => subscription.dispose(), 500);
  44. 44. Creation - Observable.from Arguments, Array, Iterable, Set, Map, String, Generated sequence Rx.Observable.from([1, 2, 3], x => x + x).subscribe( x => console.log(`onNext: ${x}`), e => console.log(`onError: ${e}`), () => console.log('onCompleted') ); // ! 2nd argument is a mapFn // => onNext: 2 // => onNext: 4 // => onNext: 6 // => onCompleted
  45. 45. Creation - Observable.from${PutHereWhatYouHave} .fromCallback, .fromPromise, fromEvent, fromNodeCallback, const firstNameInput = document.querySelector('#firstName'); Rx.Observable.fromEvent(firstNameInput, 'input') .pluck('target', 'value') .subscribe(e => console.log(e));
  46. 46. Hot ‘n cold
  47. 47. const source = Rx.Observable.interval(1000) .map(val => val + 1) .take(10); source .subscribe(val => console.log('first: ' + val)); setTimeout(() => { source .subscribe(val => console.log('second: ' + val)); }, 5000); // "first: 1" // "first: 2" // "first: 3" // "second: 1" // "first: 4" // "second: 2" // ... const source = Rx.Observable.interval(1000) .map(val => val + 1) .take(10) .publish() .refCount(); source .subscribe(val => console.log('first: ' + val)); setTimeout(() => { source.subscribe(val => console.log('second: ' + val)); }, 5000); // "first: 1" // "first: 2" // "first: 3" // "second: 3" // "first: 4" // ...
  48. 48. Hot - Live stream .publish() + .refcount() Cold - Recorded video by default
  49. 49. Query!
  50. 50. .debounce | .throttle // https://remysharp.com/2010/07/21/throttling-function-calls function throttle(fn, threshhold, scope) { threshhold || (threshhold = 250); var last, deferTimer; return function () { var context = scope || this, now = +new Date, args = arguments; if (last && now < last + threshhold) { clearTimeout(deferTimer); deferTimer = setTimeout(function () { last = now; fn.apply(context, args); }, threshhold); } else { last = now; fn.apply(context, args); } }; } window.addEventListener('resize', throttle(function (event) {console.log('resized');}), false); Rx.Observable.fromEvent(window, 'resize') .throttle(250) .subscribe(val => console.log('resized', window. innerWidth))
  51. 51. .map and .flatMap Rx.Observable.fromArray(['good', 'evening', 'ng- party!']) .map(item => item.toUpperCase()) .subscribe(val => console.log(val)); // "GOOD" // "EVENING" // "NG-PARTY!" Rx.Observable.fromArray(['good', 'evening', 'ng- party!']) .map(item => Promise.resolve(item.toUpperCase())) .subscribe(val => console.log(val)); // [object Object] { ... }, [object Object] { ... }, [object Object] { ... } Rx.Observable.fromArray(['good', 'evening', 'ng-party!']) .flatMap(item => Promise.resolve(item.toUpperCase())) .subscribe(val => console.log(val)); // "GOOD" // "EVENING" // "NG-PARTY!"
  52. 52. .takeUntil const intervalSource = Rx.Observable.interval(500) const source = Rx.Observable .fromEvent(document.querySelector('#toggle-stream'), 'click'); source .pluck('target', 'checked') .filter(val => val) .flatMapLatest(() => intervalSource.takeUntil(source)) .subscribe(val => console.log('isChecked?', val),)
  53. 53. .reduce or .scan Rx.Observable.fromArray(['It', 'is', 'time', 'for', 'beer','ng-party!']) .reduce((p, c) => p + ' ' + c, '') .subscribe(val => console.log(val.trim())); // "It is time for beer ng-party!" Rx.Observable.interval(500) .timeInterval() .pluck('interval') .reduce((p, c) => p + c, 10000) .subscribe(val => console.log(val)); ? ? ? ? ? ? ? ?
  54. 54. .reduce or .scan Rx.Observable.fromArray(['It', 'is', 'time', 'for', 'beer','ng-party!']) .reduce((p, c) => p + ' ' + c, '') .subscribe(val => console.log(val.trim())); // "It is time for beer ng-party!" Rx.Observable.interval(500) .timeInterval() .pluck('interval') .scan((p, c) => p + c, 10000) .subscribe(val => console.log(val)); // 10502 // 11001 // 11501 // 12001
  55. 55. Versions
  56. 56. github.com/Reactive-Extensions/RxJS: v4.0.7 github.com/ReactiveX/RxJS: 5.0.0-alpha.14
  57. 57. RxJS Next npm install rxjs-es import Rx from 'rxjs/Rx'; Rx.Observable.of(1,2,3) import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/map'; Observable.of(1,2,3).map(x => x + '!!!'); // etc import {Observable} from 'rxjs/Observable'; import {map} from 'rxjs/operator/map'; Observable.of(1,2,3)::map(x => x + '!!!'); // etc /* ES7 */ import { map, takeWhile, forEach } from "iterlib"; getPlayers() ::map(x => x.character()) ::takeWhile(x => x.strength > 100) ::forEach(x => console.log(x)); /* ES6 */ import { map, takeWhile, forEach } from "iterlib"; let _val; _val = getPlayers(); _val = map.call(_val, x => x.character()); _val = takeWhile.call(_val, x => x.strength > 100); _val = forEach.call(_val, x => console.log(x));
  58. 58. Advanced topics Re-play Backpressure Window ForkJoin Schedulers Generators Rx Testing, Virtual Time, Marbles WebSocketsSubject
  59. 59. Use cases Sane workflows with DOM Events (mousemove, keypress, drag and drop) UI Manipulation API Communication State management (Components, AppState, Dispatching) Set operations (map, filter, scan) Transducers
  60. 60. Alternative and affiliates
  61. 61. Bacon, Kefir
  62. 62. Angular 2
  63. 63. github.com/acdlite/redux-rx
  64. 64. garbles/yolk
  65. 65. Resources
  66. 66. xgrommx.github.io/rx-book rxmarbles.com egghead.io gitter.im/Reactive-Extensions/RxJS
  67. 67. Q & A
  68. 68. Thank you @vireliam #devsUnited

×