AngularJSとFluxと
RiotJSと
2015/10/28 GotandaJS #
@mizuki_r
Profile
account.
twitter: @mizuki_r
github: ry_mizuki
role.
フロントエンドエンジニア
tags.
AngularJS, RiotJS, Backbone,
hariko, angular-period, etc
Theme
• AngularJSで書いたアプリをFlux化した話
• Flux化したAngularJSアプリにRiotJS入れた話
AngularJSで書いたアプリ
をFlux化した話
What is Flux?
Flux s architecture
https://facebook.github.io/flux/docs/overview.html
Flux s architecture
• Facebookが提唱したアーキテクチャ
• データの流れを一方向に限定する
• Store, View, Dispatcherの責務がActionという
単位で処理を回す
Flux s architecture
https://github.com/facebook/flux/tree/master/examples/flux-todomvc/#structure-and-data-flow
Why Flux
Why Flux?
• modelの管理に疲れた
• データ構造と責務分担の分類の考察
• 急なデータの変更、Viewの変更
• controllerでmodelを管理しがち
• modelとmodelの連携
• controllerの抽象化が雑に…
所謂MVCの運用には
高度な訓練と
高い意識が必要なのでは?
もっと低意識で運用したい!
I thought…
ぼくのかんがえたさいきょうの…
• Dispatcherは自前でObserver定義
• ViewとActionCreator, Storeは一対
• ドメインの定義はViewにすべて移譲
• ActionCreatorは外部との連絡用
• API通信はngResourceをwrapしてrepository
として分離
• actionにする前にデータ整形を行うメソッドを
かます
ぼくさいFlux arch
ぼくさいFlux arch
import * as action_creator from '../action-creators/example'
import store from '../stores/example'
class ExampleCtrl {
constructor ($scope) {
this.onReceiveData = this.onReceiveData.bind(this)
this.onDestroy = this.onDestroy.bind(this)
store.addReceiveDataListener(this.onReceiveData)
$scope.$on('$destroy', this.onDestroy)
action_creator.init()
}
select () {
action_creator.select()
}
onReceiveData () {
this.data = store.getData()
}
onDestroy () {
store.removeReceiveDataListener(this.onReceiveData)
}
}
angular.module('example').controller('ExampleCtrl', ExampleCtrl)
import dispatcher from '../dispatcher'
import action_types from '../action-types'
import injector from '../injector'
export function init () {
dispatcher.handleViewAction({
type: action_types.INIT_EXAMPLE_VIEW,
})
var Repository = injector.get('ExampleRepository')
Repository.fetch().then((data) => {
dispatcher.handleApiAction({
type: action_types.RECEIVE_EXAMPLE_DATA,
data
})
})
}
export function select () {
dispatcher.handleViewAction({
type: action_types.SELECT_EXAMPLE_VIEW,
})
var Repository = injector.get('ExampleRepository')
Repository.post().then((data) => {
dispatcher.handleApiAction({
type: action_types.POST_SELECT_EXAMPLE_DATA,
data
})
})
}
conclusion
• ViewをActionCreatorとStoreに抽象化できた
• コードが冗長になり、量が増えた
• 初期開発コストは高いが更新の手間などは減っ
た
ViewをActionCreatorと
Storeに抽象化できた
…あれ?
Angularじゃなくてもよくね?
Flux化したAngularJSアプ
リにRiotJS入れた話
What is RiotJS?
RiotJS
• Reactライクのユーザインタフェースライブラリ
• とっても小さい
• Virtual-DOM
• JavaScript in HTML
<todo>
<!-- layout -->
<h3>{ opts.title }</h3>
<ul>
<li each={ item, i in items }>{ item }</li>
</ul>
<form onsubmit={ add }>
<input>
<button>Add #{ items.length + 1 }</button>
</form>
<!-- logic -->
<script>
this.items = []
add(e) {
var input = e.target[0]
this.items.push(input.value)
input.value = ''
}
</script>
</todo>
http://riotjs.com/ja/
ファイルサイズ
Reactの約1/19!
つまり…
• 小さいし必要最小限の機能
• 細かいViewの制御なら十分なAPI
• 明示的な更新が可能なI/F
• Component系なので最小限の変更範囲
• 書きやすそうなJSX
Why is RiotJS?
AngularJSへの不満…
• $applyが重い
• 暗黙的な$digestの管理が辛い
$applyが遅い
• 式を受け取りViewを更新するかを判定
• 更新する場合は`$scope.$digest()` を実行
• $http, $timeoutなどのAPIが内部的に利用
• 登録されているすべてのリスナを評価する
• 遅い評価式を登録してしまうと更新のたびに…
暗黙的な$digestが辛い
• $http, $timeoutなどAPIが暗黙的に発行する
• 発行しないAPIもある
• 自前で作った機能は$scope.$apply等が必要
• たまたまうまく更新がされるケース
• digest中にdigestを発行すると死ぬ
つまり…
• 特定のView以下で更新したい
• 短いサイクルでの更新
• 毎秒すべてのViewを評価してどうする
• 明示的に更新したい
• 必要ないところで評価されても
• 更新したいタイミングは僕らが決めたい
Angular with Riot
RiotJSの役割
• 末端のViewの更新サイクルの管理
• 毎秒更新が発生するもの
• ホバーなどサイクルが短いもの
• ユーザアクションのハンドルと他のViewとの連
携はFluxベースのアーキテクチャで吸収
• RiotからAngularのViewは参照しない
directive
angular.module('example', []).directive('todo', function () {
return function () {
riot.mount('todo')
}
})
directive化することで、templateから参照できる。
outside injector
exports.get = function (name) {
return angular.element(document).injector().get(name)
}
injectorをAngularの管理外から参照できるように
入れてみた結果
• 「遅い」と言われてた部分が解消(体感的に)
• ぶっちゃけRiotJSが早いわけじゃない
• むしろ状況次第ではAngularより遅い
• $digest漏れや$applyの遅延による「遅く見え
る」が減少した
• RiotJS、以外と書きやすい
Conclusion
Conclusion
• FluxによるViewの抽象化事例を紹介
• Viewの単位でコードを管理できるので、追加・更新・削
除が思いの外簡単になった
• でもコード量は増えた
• AngularJSとRiotJSの共存事例を紹介
• 目に見えて反応が違った
• RiotJSは必要最小限で使う分にはかなり使い勝手良い
• 個人的にはRiotJSXはもっと使って行きたい
Next Generation
• Fluxでの責務分担のあり方をもうちょっと考え
たい
• いずれこれは二層式に集約されていくのだろう
なと
• ServiceWorker上で扱えるレベルのロジック
の抽象化
• メインスレッドを綺麗にしてUIのパフォーマン
スあげたい
ご清聴ありがとうございました

AngularJSとFluxとRiotJSと