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

RxJS概要とリアクティブ アーキテクチャ

Avatar for dsuket dsuket
March 21, 2016

RxJS概要とリアクティブ アーキテクチャ

ng-japan2016でのRxJSの話

Avatar for dsuket

dsuket

March 21, 2016

More Decks by dsuket

Other Decks in Technology

Transcript

  1. Functional Reactive programming The introduction to Reactive Programming you've been

    missing ݴ͍͍ͨ͜ͱ͸શ෦͜͜ʹ͋Δ ʲ຋༁ʳ͋ͳ͕ͨٻΊ͍ͯͨϦΞΫςΟϒϓϩάϥϛϯάೖ໳
  2. ؔ਺ܕϦΞΫςΟϒϓϩάϥϛϯά (FRP) ͱ͸? ʮStackoverflowͷ໛ൣతղ౴ʯ Conal Elliott • ࣌ؒΛ͔͚ͯμΠφϛοΫʹมԽ͢Δ஋͸ɺϑΝʔετΫϥεͷ ஋Ͱ͢ɻͦΕΒΛؔ਺ͷ in/out

    ʹͯ͠૊Έ߹ΘͤΔ͜ͱ͕Ͱ͖· ͢ɻ͜ΕΛ Behavior ͱݺͼ·͢ɻ • Behavior ͸ɺ੩తͳಈ࡞΍࣌ܭͷΑ͏ͳ࣌ؒͱ͍͍͔ͬͨͭ͘ͷ ϓϦϛςΟϒͳ΋ͷ͔Βߏஙͨ͠ޙɺॱ൪·ͨ͸ฒྻʹ઀ଓʹ͠ ·͢ɻnݸͷ Behavior ͸ɺ࿈ଓͨ࣌ؒ͠ͷΑ͏ͳ཭ࢄతͳ nݸͷ ؔ਺ʹΑͬͯ߹੒͞Ε·͢ɻ • ͦͷ ཭ࢄతݱ৅Λදͨ͢Ίʹ ༗ݶ·ͨ͸ແݶʹग़ݱ͢Δετ ϦʔϜΛ࣋ͭ Event ͕͋Γ·͢ɻEvent ͸࣌ؒͱ஋ͷϖΞͰ͢ɻ ݩMSͷResearcherͰFRPͷ࢝૆ͱݴΘΕΔConal Elliottͷղઆɻ
 Α͘ࢀর͞ΕΔ͕ɺ৽ਓ޲͖Ͱ͸ͳ͍
  3. ؔ਺ܕϦΞΫςΟϒϓϩάϥϛϯά (FRP) ͱ͸? "Rx = Observables + LINQ + Schedulers”

    ɾObservables: σʔλετϦʔϜ
 ɾLINQ(Language-Integrated Query): ΫΤϦ
 ɾSchedulers: ฏߦੑ੍ޚ ͱͯ΋ॏͨ͘ɺզʑΛࠞཚͤ͞ΔϚΠΫϩιϑτతͳ΋ͷͩɻ
  4. Push vs Pull Observable͸ϒϩοΫͤͣʹෳ਺ͷ஋Λ
 ϦΞΫςΟϒʹॲཧͰ͖ΔɻPromise++ What are the Reactive Extensions

    for JavaScript (RxJS)? ୯Ұͷ໭Γ஋ ෳ਺ͷ໭Γ஋ 1VMMಉظతର࿩ܕ 0CKFDU "SSBZ 4FU .BQ 0CKFDU 1VTIඇಉظ3FBDUJWF 1SPNJTF 0CTFSWBCMF
  5. Rxͷ஥ؒୡ Languages • RxJava, RxJS, Rx.NET, RxScala, RxGroovy, RxJRuby, •

    UniRx, RxCpp, RxClojure, Rx.rb RxPY, RxKotlin, RxSwift Platforms and frameworks • RxNetty, RxAndroid, RxCocoa http://reactivex.io/languages.html
  6. Other FRP libraries • Bacon.js • RxJSͷޙൃ FRPϥΠϒϥϦɻRxJSΑΓ΋Ұ؏ੑ͋Γɺ ࢖͍΍͍͕͢ύϑΥʔϚϯεʹগ͠೉͋Γʁ •

    Kefir • Bacon.jsͷ͞ΒʹޙൃɻলαΠζɺলϝϞϦɻ ͲͪΒ΋ES7 Observableͱ͸ҟͳΓͦ͏ͳͨΊɺࠓޙ͕ඍົ
  7. RxJSͷ஫ҙ • ݱࡏ RxJS ͸ 4ܥͱ5ܥ͕͋ΓɺϦϙδτϦ͕ҧ͏ • 4ܥ: Reactive-Extensions/RxJS •

    5ܥ: ReactiveX/RxJS ʢ·ͩbeta2ɻAngular2Ͱ࠾༻ʣ • v5ͰAPI͕౷ഇ߹͞Εͯ݁ߏมΘͬͯΔʂ • ᷿ͷυΩϡϝϯτ͸΄ͱΜͲ͕4ܥɻ֓೦͸େ͖͘͸มΘͬͯͳ͍͕ɻɻ • Migrating from RxJS 4 to 5 ඞಡ • ·ͩυΩϡϝϯτ͞Εͳ͍෺΋ଟ͍ͷͰιʔεಡΉඞཁ΋ • ຊࢿྉ͸ v5 ରԠͰઆ໌͠·͢
  8. RxJSͷجຊ RxJS = Observables + Operators + Schedulers • Observable:

    σʔλετϦʔϜ
 Rx.Observable.of / from / create ͳͲͰࣗ༝ʹ࡞ΕΔɻ • Operators: ΫΤϦ
 mapͱ͔filterͱ͔ɺObservableΛૢ࡞͢Δؔ਺ • Schedulers: ฒߦੑͷίϯτϩʔϧ
  9. ؆୯ͳαϯϓϧ const stream = Rx.Observable.range(0,5) // 0,1,2,3,4 .map(x => x

    * 3) // => 0,3,6,9,12 .filter(x => x%2); // => 3,9 stream.subscribe({ next: x => console.log(‘Next:' + x), error: err => console.error('Error:', err), complete: () => console.log('Completed'), }); => "Next:3" => "Next:9" => "Completed"
  10. ࢀߟ: ͦͷଞΑ͘ಡΉࢿྉ • RxJS/observable.md at master · Reactive-Extensions/RxJS • v4ͷAPIυΩϡϝϯτ

    • RxJS/MIGRATION.md at master · ReactiveX/RxJS • v4͔Β5΁ͷϚΠάϨʔγϣϯΨΠυ • RxJS/src/operator at master · ReactiveX/RxJS • v5 ͷΦϖϨʔλҰཡʢsrcʣ • RxJS Advent Calendar 2015 • @bouzuya ͞Μͷᕒ਎ͷಠΓΞυΧϨ
  11. ੜ੒ • Rx.Observable.of • ୯Ұͷ஋ΛͱΓɺͦΕΛฦ͢ετϦʔϜΛੜ੒ • just/return ͸ofʹٵऩ͞Εͨ • Rx.Observable.from

    • ഑ྻɺPromiseɺObservableͳͲΛऔΓɺͦΕΒෳ਺ͷ஋ͷετ ϦʔϜΛੜ੒ • Rx.Observable.range / repeat • ࢦఆൣғɺ·ͨ͸஋ͷ࿈ଓͨ͠ετϦʔϜΛੜ੒ • Rx.Observable.interval / timer • ҰఆִؒͰ܁Γฦ͢ • Rx.Observable.create • subscriberΛҾ਺ʹ೚ҙͷ஋Λྲྀ͢ετϦʔϜΛੜ੒
  12. ม׵ • map (select) • ஋Λม׵͢Δ • select ͸ v5

    Ͱഇࢭɻ஋ΛऔΔ৔߹͸ɺmapTo ʹɻ • mergeMap (flatMap) • map ݁Ռ͕Observable΍഑ྻͷ৔߹Α͘࢖͏ • v5 Ͱ mergeMap ʹɻObservableΛऔΔ৔߹͸ɺmergeMapTo ʹɻ • scan • reduceͬΆ͍͕ɺ౎౓஋Λྲྀ͢ • groupBy • άϧʔϓ෼͚ʢ෼ׂʣ͢Δ • buffer / bufferCount / bufferTime • ਺΍࣌ؒͰΠϕϯτ·ͱΊΔ
  13. ϑΟϧλϦϯά • filter (where) • ஋ͳͲͰϑΟϧλϦϯά͢Δ • where ͸ v5

    Ͱഇࢭɻ • first / last • ࠷ॳ΍࠷ޙͷ஋͚ͩΛऔΔ • skip / skipLast • ࢦఆͷnݸΛඈ͹͢ɻskipLast ͸ v5Ͱഇࢭ • take / takeLast • ࢦఆͷnݸΛऔಘ͢ΔɻtakeLast͸࠷ޙͷnݸɻ • distinct • ϢχʔΫʹͯ͠औಘ͢Δɻ • sample / debounce • ࢦఆִؒຖͷ࠷ޙͷ஋Λऔಘ͢Δɻ
  14. ݁߹ • startWith • ॳظ஋Λ࠷ॳʹૠೖ • merge • ετϦʔϜΛ݁߹͢Δɻෳ਺Ͱ΋OK •

    switch • ετϦʔϜΛॱʹྲྀ͢ • combineLatest • ෳ਺ͷετϦʔϜͷ࠷ޙͷ஋Λ݁߹͢Δɻ • Ͳ͔͜1ͭͰ΋དྷΕ͹ɺଞͷετϦʔϜͷ௚ۙͷ஋ͱ݁߹͢Δ • zip • ෳ਺ͷετϦʔϜͷ࠷ޙͷ஋Λ݁߹͢Δɻ • શ෦ἧ͔ͬͯΒग़ྗ͞ΕΔɻ • and / then / when • v5Ͱഇࢭʁ
  15. ղઆ1: randomStream const randomStream = Rx.Observable .create(observer => { observer.next(!Math.floor(Math.random()*2));

    observer.complete(); }); Everything is a stream Observable.create ͰɺϥϯμϜʹtrue/falseΛฦ͢ ετϦʔϜΛ࡞੒
  16. ղઆ2: zundokoStream const zun = Rx.Observable.of('ズン'); const doko = Rx.Observable.of('ドコ');

    return randomStream .flatMap(val => (val ? zun : doko)); “ζϯ” ͱ ”υί” Λฦ͢ετϦʔϜΛ࡞੒͠ɺ randomStreamͷ஋ʹΑͬͯ੾Γସ͑Δɻ
  17. ղઆ3: intervalStream return Rx.Observable.interval(400) .mergeMapTo(zundoko) .do(val => console.log(val)) .bufferCount(5, 1)

    .takeWhile(val => val.join('') !== 'ズンズンズンズンドコ'); Observable.interval Ͱ 400msຖʹ܁Γฦ͢ετϦʔϜΛ࡞੒͠
 ͦΕΛmargeMapToͰzundokoStreamʹஔ͖׵͑Δɻ
 doͰ్த݁ՌΛग़ྗͭͭ͠ɺbufferCount ͰskipΛ1Ͱ5ݸηο τɻtakeWhile Ͱ໨తͷจࣈྻʹͳΔ·Ͱ܁Γฦ͢ɻ
  18. ղઆ4: subscribe const source = createStream(); source.subscribe({ next: () =>

    {}, error: err => console.log('Error: ', err), complete: () => console.log('キ・ヨ・シ!'), }); ࡞੒ͨ͠StreamΛsubscribeͯ͠ɺ׬ྃ࣌ʹจࣈ ྻΛग़ྗ͢Δɻ
  19. RxJS in Angular2 • Angular2Ͱ͸Ұ෦ͰRxJSΛ࠾༻ • HTTP • EventEmitter •

    ίϯϙʔωϯτΠϕϯτ΍HTTPϦΫΤετΛ Observableͱͯ͠ѻ͑Δʂ • ViewͰ΋ObservableΛදࣔՄೳ
  20. Angular2ͰͷReactive Architectureͷݕ౼ • Angular2ͷComponent͸ར༻͍ͨ͠ɻ֊૚Խͱؚ͔Ίɻ • MVIͷObservableத৺ͷߟ͑͸Αͦ͞͏ɻ • ComponentʹModelɼIntent૬౰ΛObservableͰೖΕͯΈΔɻ • ϞσϧΛObservableʹ͠ɺViewͰ΋ͦΕΛ࢖͏

    • ΠϕϯτϋϯυϦϯά͸AngularͷόΠϯσΟϯά͕ศརͳͷͰͦΕ Λ࢖͏ɻ • όΠϯσΟϯάΛView͔Βग़͢͜ͱ͕ඞͣ͠΋ਖ਼ղͰ͸ͳ͍ͷͰ͸ɻʢؔ৺ͱٕज़ͷ ෼཭ʣ
  21. $PNQPOFOU Angular2 MVI 6TFS .PVTF *OUFOU 0CTFSWBCMF .PEFM 
 Πϯελϯεม਺

    0CTFSWBCMF 7JFX UFNQMBUF 4DSFFO formCtrl͔ΒϢʔβʔҙਤ
 ΛΠϯςϯτͱͯ͠Observableʹ Πϯςϯτ͔Β஋ΛऔΓग़͢
 ObservableͳΠϯελϯεม਺ Observableม਺Λ
 asyncͰviewʹόΠϯυ
  22. @Component({ selector: 'bmi', styles: [require('./bmi.component.scss')], template:` <div class="bmi-calc"> <div class="weight">

    <div class="label">Weight: </div> <input id="#weight" type=“range" [ngFormControl]="weightCtrl"> {{weight$ | async}} kg </div> <div class="height"> <div class="label">Height: </div> <input id="#height" type=“range" [ngFormControl]="heightCtrl"> {{height$ | async}} cm </div> <h3>BMI is {{bmi$ | async}}</h3> </div> `, directives: [FORM_DIRECTIVES], }) bmi.component.ts
  23. export class BmiComponent { // Models private weight$; private height$;

    private bmi$; // Controls private weightCtrl = new Control(); private heightCtrl = new Control(); constructor() { // Intents const weightChanges = this.weightCtrl.valueChanges; const heightChanges = this.heightCtrl.valueChanges; // Bind intents to models this.weight$ = weightChanges.map(Number).startWith(60); this.height$ = heightChanges.map(Number).startWith(170); this.bmi$ = this.weight$.combineLatest(this.height$) .map(this.calcBmi); } calcBmi(data) { const [weight, height] = data; const heightMeters = height * 0.01; return Math.round(weight / (heightMeters * heightMeters)); } } bmi.component.ts
  24. ߟ࡯ Pros • ͳ͔ͳ͔ΩϨΠʹॻ͚ͦ͏ɻ • @Input ͳͲͰObservableΛ΍ΓͱΓͯ͠ɺComponentؒ࿈ܞ΋؆୯ ʹͰ͖ͦ͏ɻ Cons •

    ຖճ async ॻ͘ͷ͕ͪΐͬͱ໘౗͍͘͞ɻ • ͦ΋ͦ΋͜ͷॻ͖ํ͕޾ͤͳͷ͔Ͳ͏͔Α͘෼͔Βͳ͍ɻɻ • ύϑΥʔϚϯεతʹͲ͏͔ؾʹͳΔɻ • ngFor ͕ Observable Λͦͷ··ѻ͑ͳ͍ͷ͕࢒೦
  25. ༨ஊ ͖ͬ͞ͷ zundoko Λ Angular2 + MVI Ͱ࡞ͬͨ • dsuket/zundoko-angular

    • Demo લηογϣϯͰ @shumpei ͕࡞ͬͨελʔλʔΩοτ࢖͑͹͙͢Ͱ͖ͨɻ ͚Ͳɺશ෦ObservableͰ࡞Δͷ͸πϥΠŋŋŋ
 ࣌ؒͷ౎߹Ͱ݁ہී௨ͷόΠϯσΟϯάʹͳͬͨͱ͜Ζ΋
  26. ࢀߟ • Cycle.js • Reactive Data Flow in Angular 2

    • How to build Angular 2 apps using Observable Data Services - Pitfalls to avoid • Taking advantage of Observables in Angular 2 • todomvc-ng2-reactive • angular2-reactive-starter