Chaplinでのroutes登録のイベント取り回し関係をまとめました
Chaplinjsで渡されるroutesについて、イベントのpub/subの挙動を真面目に読んでいなかったところを読んだのでまとめました。
端的にいうと、イベント(route:match
)をpublishするための登録フロー(Router -> Route -> Backbone.history)とsubscribeするための登録フロー(Dispatcher -> Route)があり、監視されているURLの変更(popstateやhashchangeなど)でイベントが発火 -> Controllerのロードとactionの実行、になっています。
Application
Applicationは内部で下記のinitを実行します。
* initDispatcher
* initLayout
* initMediator
* initRouter
publishのフロー
initRouter
initRouterの中ではApplicationに渡されたroutes
とoptions
を受け取ります
@router = new Router options
として、routerを初期化し、Router#match
というメソッドを受け、渡されたroutes
を実行します。
routes
は下記のようにpattern
とtarget
(に加え必要であればoptions
)を受け、URLの変更に対して適切なControllerのactionを対応付けます。
initRouterの中では
routes? @router.match
が実行され、それぞれのmatch pattern, target
が実行されます。
match
では、
route = new Route pattern, controller, action, options
として、route
オブジェクトが作成され、その後
Backbone.history.handlers.push {route, callback: route.handler}
としてhistory handlerに登録されます。
最後にroute
が返却されますが、routes
の中では特になにも処理されていません。
routes
の中で記述したルーティングが処理される機会は、このinitRouterだけになります。
Backbone.history
では、このルーティングはどのように制御されているかというと、すべてはBackbone.historyの中だけで処理されます。
Backbone.historyは、start
メソッドが実行されると、hashChangeだけなのか、pushStateを見るのか、などのフラグ判別の処理の末、
if (this._hasPushState) {
addEventListener('popstate', this.checkUrl, false);
} else if (this._wantsHashChange && this._hasHashChange && !this.iframe) {
addEventListener('hashchange', this.checkUrl, false);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
というように、
- popstate
- hashchange
- setInterval の3つの方法でURL変化の監視が開始されます。
URLの変化に対してhistory.checkUrl
が実行されます。
この中で、setInterval
に対応するために実際にURLが変化しているかどうかのチェックが行われ、通過すると、history.loadUrl
が実行されます。
Backbone.history.loadUrl
ここでようやく、Backbone.history.handlers
に登録しておいたrouteが評価されます。
return _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
handler.callback(fragment);
return true;
}
});
handlersの中から、現在のfragment
(ざっくりURL)にマッチするものが存在するかがRoute#test
でチェックされ、マッチしたcallback
が実行される、という挙動になります。
ここでのcallback
は、前述のとおり、Chaplin.Router
でBackbone.history.handlers.push {route, callback: route.handler}
として登録されています。
Chaplin.Route#handlerでのイベントpublish
さて、Route#handler
はどうなっているでしょうか?
例えば /users/33/posts/123?fields=comments
のような fragment
が渡されると、query
も含めてパースされ最終的には
routes = {path, @action, @controller, @name, query}
というオブジェクトをつけて
@publishEvent 'router:match', route, actionParams, options
として、イベントが発行されます。
subscribeのフロー
Chaplin.Dispatcher
Chaplin.Dispatcherは初期化時にroute:match
イベントを@dispatch
で待ち受けます。
もろもろのチェックが通ると、Dispatcher#loadController(name, handler)
が発火します。
loadController
では、ついに動的なcontrollerのロードが行われます。
Applicationの初期化時にoptionsで渡したcontrollerSuffix
やcontrollerPath
が加味され、controllerのファイルパスが作成されます。
ここでのhandlerは
(Controller) =>
@controllerLoaded route, params, options, Controller
となっており、ロードされたコントローラに対して、ルーティングの結果得られたパラメタなどが渡されます。
loadControllerの中では、作成されたファイルパスに対して、define.amd
またはrequire
でcontrollerモジュールが呼び出されhandler(というかcontrollerLoaded)が実行されます。
Dispatcher#controllerLoadedとDispatcher#executeAction
その後は、controllerLoadedでControllerのインスタンスが作成され、executeActionに引き渡され、その中でaction
が実行される事になります。
そこで、ようやく各種のControllerで定義したメソッドのところに届くことになります
class SomeController extends Chaplin.Controller
someAction: (params, routes, options)->
まとめ
長くなりましたが、順序としては
- Applicationの初期化
- subscribe処理
-
route:match
のsubscribe - イベント受け取り時の
route, params, options
を元に、動的にcontrollerのロード/インスタンス化/Controller#Actionの実行
-
- publish処理
- Application#initRouter
- routes(Router#match)により、Backbone.history.handlersへの追加
- Backbone.history.startによるURL変化の監視
- handlers内のmatchするhandlerのcallbackの実行
- Route#handlerでの
route:match
イベントのpublish
となっていることを読み解きました。
Author And Source
この問題について(Chaplinでのroutes登録のイベント取り回し関係をまとめました), 我々は、より多くの情報をここで見つけました https://qiita.com/muddydixon/items/353aa1e12d684dd3dc75著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .