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
Tweet

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