Kokudoriing

技術系与太話ブログ

jQueryとイベントドリブンと私

jQueryと言えばjQuery.DeferredとjQuery.CallbacksとjQuery.Eventですよね。
おまけにDOM操作も出来るライブラリ。

恐らくjQueryバリバリ書いてらっしゃる方々は何を今更といった話しなんでしょうが、
jQuery初心者の自分にとってはjQueryのイベントドリブンが素敵過ぎて眩しいのでまとめ。


基本戦略としてイベントファースト。
一番わかり易いイベント発火点はDOM Readyイベント。
つまりプレゼンテーションに関わる部分はDOM Readyから順次イベントを検出して発火。
プレゼンテーション非依存の部分(外部の設定ファイルとか顕著)は各々適当なタイミングでイベント発火。

そんな感じで構造化すると非常にスムーズに木構造になるのでファイル構造とマッピングしやすい。
例えば index.js でDOM Ready時にサイドバーにオサレにアニメーションをかけたい場合。

jQuery(function($) {
  $('#sidebar').trigger('onRequestAnimation');
});

とし、sidebar.jsで

(function($, undefined) {
  $('#sidebar').on('onRequestAnimation', function(e) {
    // サイドバーをアニメーションする
  });
}).call(this, jQuery);

さて、まどろっこしいですね。
これは

jQuery(function($) {
  // $('#sidebar').animate(...)
});

と殆ど変わりない気がします。

じゃあ何故わざわざ別のイベントを一枚噛ませているのか。
例えばサイドバーがアニメーションするのはDOM Readyの時以外にも十分に起きるでしょう。
ユーザーがマウスオーバーするとなんとなくアニメーションしそうな感じです。
その時別に $('#sidebar').on('mouseover', function() { // this.animate(...); }) とかしてもいいんですが、

jQuery(function($) {
  $('#sidebar').on('mouseover', function() {
    this.trigger('onRequestAnimation');
  });
});

としてやればDRYですねというお話。

また、「サイドバーのアニメーションがDOM Readyイベント後に呼ばれなければならない」というのは実装のお話。
onRequestAnimationというイベントでそれを抽象化することが出来た。

でもそんな抽象化して何が嬉しいの?
なんといってもテスト容易性。
つまりサイドバーのアニメーションはonRequestAnimationを発火させれば呼び出しを保証するもの。
マウスやら何やらのイベントのバインディングとonRequestAnimationイベントの発火部分がテスト出来る。

今回の例だと単純化しすぎているので殆ど旨みがない。
でもかなり複雑化していくとサイドバーだけをテストすることがしんどくなる。
すべての動作の起点をイベントにし、
可能な限り専門化したカスタムイベントでラップするとだいぶと見渡しが良くなる。

つまり一番上のファイルでイベントを拾いまくり、
それを各々の専門化されたオブジェクトに処理を委譲するスタイル。
自然にファイル分割が進み、コンポーネント間で疎結合が進み、
(理想状態だと各コンポーネント間はイベントにのみ依存)
テストをイベントキャプチャフェーズと処理委譲フェーズで分割できる。

ちなみに処理委譲フェーズ(プレゼンテーション依存コード)のテストは死ねる。というか僕には書けない。
イベントキャプチャフェーズのテストは呼び出しテストなので、
(DOMが発生するイベントをうまく理解している限り)比較的大丈夫。