Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unidirectional Dataflow With Observables

Unidirectional Dataflow With Observables

I gave this talk at the Devs Meetup in Freiburg.

Here is the list of things I linked to in my slides:

My Twitter: http://twitter.com/kahliltweets
My Site: http://kahlil.info
My Snapchat: https://www.snapchat.com/add/kahlilsnaps

The introduction to Reactive Programming you've been missing:
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

RxJS Beyond the Basics: Creating Observables from scratch:
https://egghead.io/courses/rxjs-beyond-the-basics-creating-observables-from-scratch

Learning Observable By Building Observable:
https://medium.com/@benlesh/learning-observable-by-building-observable-d5da57405d87#.krkwhykrg

Netflix JavaScript Talks - Async JavaScript with Reactive Extensions:
https://www.youtube.com/watch?v=FAZJsxcykPs&feature=youtu.be&t=752

The Cycle.js Reducer Pattern:
http://staltz.com/reducer-pattern-in-cyclejs.html

TinyDraft (an example project):
https://github.com/kahlil/tinydraft

Artists (an example project):
https://github.com/kahlil/artists

Kahlil Lechelt

June 29, 2016
Tweet

More Decks by Kahlil Lechelt

Other Decks in Technology

Transcript

  1. BEST. FUCKING. CULT. EVVURR. Our rituals include: - writing less

    code - delete code - saying "streams" all the time
  2. WARNING This is just brief introduction to observables in order

    to give you some context. To fully understand them I have listed some resources for you to learn from: » "The introduction to Reactive Programming you've been missing" » "RxJS Beyond the Basics: Creating Observables from scratch"
  3. “Observable is a function that takes an observer and returns

    a function.” Ben Lesh (Frontend Lead Netflix, Lead Dev RxJS 5)
  4. function myObservable(observer) { const datasource = new DataSource(); datasource.ondata =

    (e) => observer.next(e); datasource.onerror = (err) => observer.error(err); datasource.oncomplete = () => observer.complete(); return () => { datasource.destroy(); }; }
  5. “An Observable is just a collection of items, over time.”

    Jafar Husain (Cross-Platform Technical Lead Netflix)
  6. const stream = Rx.Observable.fromArray([1, 2, 3, 4, 5, 6]); stream

    .map(x => x * 10) .filter(x => x > 30) .scan((acc, x) => acc + x, 0) .subscribe( x => console.log(x), // => 40, 90, 150 err => console.error(error), () => console.log('completed') );
  7. Search Wikipedia Example function searchWikipedia (term) { // makes request

    - returns promise } const $input = $('#textInput'); // Get all distinct key up events from the input and only fire if long enough and distinct const keyup = Rx.Observable.fromEvent($input, 'keyup') .map(e => e.target.value) .filter(text => text.length > 2) .debounce(750 /* Pause for 750ms */ ) .distinctUntilChanged() // Only if the value has changed .flatMapLatest(searchWikipedia) .subscribe(/* write data to DOM */); See working example here.
  8. uni • di • rec • tion • al Functioning,

    moving, or responsive in a single direction. da • ta • flow Path taken by data within a device, network, or organization, as it moves from its source to a data repository or a data user.
  9. This is why: » data flows in one direction »

    side effects live at the edges of the application.
  10. » Cycle.js uses the Cycle.js reducer pattern and drivers »

    Elm uses the updater pattern and ports » Redux uses a reducer pattern and middleware
  11. Why do we do all this? » keeps growing and

    big apps manageable » devs stay in control of the code
  12. Unidirectional Dataflow with RxJS Observables Welcome to the cult! All

    doors and exits have been locked for your safety. (we will wait here for the space ship !)
  13. How does that all fit together? How do we implement

    a unidirectional dataflow with Observables?
  14. Cycle.js does a good job of tying these two concepts

    together They implement a unidirectional dataflow pattern called MVI: “MVI is a simple pattern to refactor the main() function into three parts: Intent (to listen to the user), Model (to process information), and View (to output back to the user).” Cycle.js Docs
  15. Cycle.js Reducer Pattern And MVI comes with the Cycle.js reducer

    pattern which continuously manages and holds state using Observables. Same as update pattern in Elm. Same as reducers in Redux.
  16. Cycle.js Reducer Pattern » central to any type of unidirectional

    dataflow you would model with Observables » you can model Flux, Redux or MVI using this pattern » the rest is just slightly differently organized code
  17. 1.Create action streams (intent / user actions) .fromEvent(), .fromPromise() .create()

    ... 2.Merge them into one big fat stream of actions (Dispatcher) .merge() or Rx.Subject 3.in your store or model function, .filter() for the action that you are interested in 4..map() action to corresponding reducer function 5..scan() over the resulting stream of reducer functions and apply each reducer function on the current state
  18. Dispatcher const dispatcher$ = new Rx.Subject(); function dispatch(stream, action) {

    return stream .map(action => ({ type: action, payload: action.payload }) .subscribe(action => dispatcher$.next(action)); }
  19. Reducer Pattern const openMail$ = dispatcher$ .filter(action => action.type ===

    'OPEN_MAIL') .map(action => { return state => state.map(mail => { if (mail.id === action.id) { mail.open = true; } return mail; } }); return Rx.Observable .merge(openMail$, /* other action reducer streams */) .scan((state, modFn) => modFn(state), []);
  20. LET'S SEE SOME CODE A simple example and naive implementation

    using RxJS, jQuery and ES2015: github.com/kahlil/artists A more complicated example using Angular 2, RxJS, TypeScript and a little helper library I made: github.com/kahlil/tinydraft