0-9
jQueryのliveやdelegateは実際何をやってるのか

jQueryにはイベント制御のAPIとして、clickやmouseoverの元になるbindの他に、同じような呼び出し方のliveやdelegateが提供されている。
bindはDOM APIで提供されているaddEventListenerのwrapperだが、liveは以下のような実装になっている。

1. 第一引数のイベント名でdocument objectにlive用のイベントハンドラーをbindする
2. 1で設定したイベントハンドラー内でdocument object内に存在する要素上で発生したイベントを全てキャッチする
・イベントの発生元要素がbind時に設定されたセレクタに一致する場合、第二引数に指定されたユーザーのイベントハンドラーを呼び出す

これはもともと「多量の要素に対してbindするとUIをロックしてしまう」という問題の対策として知られていた手法だが、liveはそれをjQuery APIとして標準化したもの。

こういう実装になっているので、liveはbindと比べて以下のような特長がある。

・イベント設定時に要素が存在している必要がない

liveはよく「セレクタに対してイベントを設定するようなもの」と言われるが、実際セレクタはイベント設定時ではなくイベント発生時に評価されるためイベント設定時に要素があるかどうかは関係がない。
このため、live設定後に逐次追加される要素に対してのイベントや、DOM構築前にイベントを設定する場合などに使用できる。

・要素数とイベントハンドラーの設定回数が比例しない
通常のbindは対象とする要素に対して個々にイベントを設定するため、要素数に比例してbind時の負荷が高くなる問題があるが、liveはdocument objectに対して一度bindするだけなので要素数とイベント設定時の負荷は連動しない。
ただし、これはlive呼び出し前に$()している点は含めていない。
この問題を解決するにはdelegateを使うか、あえてDOM構築前の要素が取得できない段階でliveを設定することで回避できる。
(もしくは、jQuery内部で使用している特殊な形式のセレクタを使うこともできるが、APIドキュメント化されていないためオススメしない)

・イベントの発生順が通常のbindされたイベントハンドラー後
実装上、liveで設定されたイベントハンドラーはbindで設定されたイベントハンドラーの後に呼び出される。
このため、liveで設定したイベントからbindで設定したイベントをキャンセルする事ができない。
(bindで設定したイベントからliveで設定したイベントをキャンセルすることは可能。また、liveイベントからブラウザの標準動作をキャンセルすることは可能)

・イベント処理自体の負荷は増加
発生したイベントに対して「発生元要素が対象セレクタに一致するか?」を確認するため、通常bindしたイベント処理に対して負荷が高くなる。
通常そこまで問題になるレベルではないが、リソースが限られた環境や、全体に負荷が高い場合には注意。

・設定されたイベントは全てjQuery内部で処理される
bindを使用したイベント設定の場合、対象となる要素上で発生したイベントのみjQuery内で処理されるが、liveを使用したイベント設定の場合、全ての要素上で発生するイベントがjQuery内で処理されて、発生元要素が対象要素の場合、イベントハンドラーを呼び出す。
このような実装になっているため、mouseover、scroll、resize等の全体で発生頻度が高いイベントをliveで設定した場合、対象要素と関係ない要素で発生したイベントでもパフォーマンスに影響を与える可能性がある。

これまで上げた問題点の内、パフォーマンスに関してはdelegateを使うことで解決できる場合がある。

delegateはliveとbindの中間のような実装で、$()で指定した要素にbindはするが、バブリングしてきたイベントの発生元要素が第一引数のセレクタに一致した場合だけイベントハンドラーを呼び出す。
つまり、document objectに対してdelegateを行えば、liveを行ったのと同じような動作になる。
delegateはliveに対して以下のような特長がある。

・初期のイベント設定が高速
liveは最初に指定する$()の要素を実際は使用しないが、jQueryの仕様上$()で指定したセレクタに一致する要素は取得してしまう。
しかし、liveは大量の要素に対して素早くイベントを設置するために使われることが多いので、このままだと持ち味を生かすことができない。
これに対してdelegateは$()で指定した要素の取得は行うが、イベント発生元要素の指定はセレクタ文字列を渡すだけなので実際要素の取得は行わない。
このため、今後jQueryではlive方式ではなく、delegate方式が主流になると思う。
(jQuery 1.7で採用されたonもliveはおまけみたいな実装だし)
ちなみに、この問題に関しては「DOM構築前のまだ要素が存在しない段階でliveを行う」方法でも回避可能で、個人的にもこの方法をよく使っている

・bindする要素を指定できる
liveはdocument objectにbindする実装上、要素を破棄してイベントが解除されるということがほぼなく、JSで画面遷移を実装した場合各画面ごとのイベント破棄を確実に行う必要がある。
これに対してdelegateはbindする要素を指定することができるので、画面遷移時に破棄される要素を対象とすればイベントの破棄をあまり考える必要がない。
ただ、これはあまり嬉しい場面も多くないので、大抵はイベント設定の高速化が目的になるだろう。

delegateはliveと同じような説明でぱっと見何に使うのか分かりにくいが、後から追加されただけあってliveの問題点を解決する形になっている。
jQuery 1.7で追加されるonでもliveはおまけ的な扱いになっているし、個人的にもこれから触るならliveは忘れてdelegateメインで使うほうがいいと思う。
(まあでも書式が分かりやすいので、パフォーマンスに問題ない形で使ってるけど)

  1. cocoaproject0-9からリブログしました
  2. sanemat0-9からリブログしました
  3. y-usyoichiからリブログしました
  4. inter-milano-69syoichiからリブログしました
  5. cocoaprojectsyoichiからリブログしました
  6. ken0205syoichiからリブログしました
  7. infofgssyoichiからリブログしました
  8. hidksyoichiからリブログしました
  9. hsmtsyoichiからリブログしました
  10. iguusyoichiからリブログしました
  11. neos21syoichiからリブログしました
  12. kosnsyoichiからリブログしました
  13. syoichi0-9からリブログしました
  14. atm09td0-9からリブログしました
  15. 0-9の投稿です