Promiseもコールバックも使ってないのにDispatcherのwaitForで順番の制御ができる。どういう事なのか気になったので調べた。


flux.Dispatcher

Reactはなんとなく使えるようになった気がしたので、fluxでやろう、StoreとかActionとかどう書くんだと調べてて、とりあえずflux npmというFacebookの中の人によるfluxアーキテクチャの説明とDispatcherが一つだけ入っているnpmを見ていた。

Dispatcherは使ってみた感じ、イベント名が無いEventEmitterみたいな感じで、登録順に実行される。

flux = require 'flux'
Dispatcher = new flux.Dispatcher

Dispatcher.register (action) ->
console.log "1 - #{JSON.stringify action}"

Dispatcher.register (action) ->
console.log "2 - #{JSON.stringify action}"

Dispatcher.register (action) ->
console.log "3 - #{JSON.stringify action}"

Dispatcher.dispatch
actionType: 'add-food'
food: 'beef'

Dispatcher.dispatch
foo: 'bar'
1 - {"actionType":"add-food","food":"beef"}
2 - {"actionType":"add-food","food":"beef"}
3 - {"actionType":"add-food","food":"beef"}
1 - {"foo":"bar"}
2 - {"foo":"bar"}
3 - {"foo":"bar"}


waitFor([id…])


なんかwaitForにregisterメソッドから返ってくるIDを渡すと、そのコールバック呼び出しの順序を制御できるらしい。便利そう

flux = require 'flux'
Dispatcher = new flux.Dispatcher

wait_ids = []

Dispatcher.register (action) ->
Dispatcher.waitFor wait_ids
console.log "1 - #{JSON.stringify action}"

wait_ids.push Dispatcher.register (action) ->
console.log "2 - #{JSON.stringify action}"

Dispatcher.register (action) ->
console.log "3 - #{JSON.stringify action}"

Dispatcher.dispatch
actionType: 'add-food'
food: 'beef'

2 - {"actionType":"add-food","food":"beef"}
1 - {"actionType":"add-food","food":"beef"}
3 - {"actionType":"add-food","food":"beef"}

何度もwaitFor

1つのコールバック内でwaitFor→なんか処理→またwaitFor→なんか処理 ができる。気持ち悪い。
flux = require 'flux'
Dispatcher = new flux.Dispatcher

wait_ids = []
wait_ids2 = []

Dispatcher.register (action) ->
Dispatcher.waitFor wait_ids
console.log "1 - #{JSON.stringify action}"
Dispatcher.waitFor wait_ids2
console.log "done!"

wait_ids.push Dispatcher.register (action) ->
console.log "2 - #{JSON.stringify action}"

wait_ids2.push Dispatcher.register (action) ->
console.log "3 - #{JSON.stringify action}"

console.log "wait_ids #{wait_ids}"
console.log "wait_ids2 #{wait_ids2}"

Dispatcher.dispatch
actionType: 'add-food'
food: 'beef'

wait_ids  ID_2
wait_ids2 ID_3
2 - {"actionType":"add-food","food":"beef"}
1 - {"actionType":"add-food","food":"beef"}
3 - {"actionType":"add-food","food":"beef"}
done!


waitForの実装

https://github.com/facebook/flux/blob/2.0.2/src/Dispatcher.js#L154-L177

waitForというより、指定idのコールバックを先に実行しているだけ。待っているように見えてるだけだった。

そもそもDispatcher.registerにはEventEmitterのようにイベント名は登録できないので、dispatchしたらregister済みの全てのコールバック関数は登録順に即実行される。(actionTypeなどのプロパティで自分宛てなのか判定してねという作法になってる)

dispatchすると、コールバックは実行直前に自分のidにisDispatchingフラグを立てる。
コールバック内でwaitFor([id…])を呼ぶと、id指定したコールバックをその場で実行しようとする。
対象がisDispatchingの場合は次のidを見る。
waitForで指定されたidのコールバックの中で、さらにwaitForが呼ばれたら再帰的にまた同じことをやる。

自分のidにはpendingフラグが立っていて、pendingなコールバック間でwaitForがループするとCircular dependency detected while…というエラーがthrowされる。

waitFor指定したコールバックの呼び出しが完了したら、そのまま処理が続くので順番が制御できる。