Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2010-02-04

DOM Mutation Events は非同期にして使おう

04:35

知ってる人にとってはどうってことない基本的なこと。


DOM 3 Events で deprecated 扱いになった DOM Mutations Events だけど、まだ代替品は無いわけで、これを使わざるをえない。

DOM Mutation Events は同期的なイベントなので、うまく使わないと全体の動作がモッサリしてしまうのが難点。

つまり、ループで DOM ツリーを弄るようなスクリプトだと、ループ中に毎回呼ばれて大変なことになる。

特に同期的動作が必要でない場合は setTimeout を入れてしまったほうがいい。

// イベントリスナーを付ける
document.addEventListener('DOMNodeInserted', nodeInsertedHandler, false);

function nodeInsertedHandler() {
  // ハンドラー内でイベントリスナーを削除する
  document.removeEventListener('DOMNodeInserted', nodeInsertedHandler, false);

  setTimeout(function() { // 内容は別イベントに分ける
    /* 処理 */

    // イベントリスナーを復活させる
    document.addEventListener('DOMNodeInserted', nodeInsertedHandler, false);
  }, 10);
}

これだと何回ループが回っても DOMNodeInserted は最初に1回出るだけ。しかも同期処理中でやってることは setTimeout を置くだけなのであまり重くならない。

もし挿入された要素が使いたいときは適当なスタックを用意。

document.addEventListener('DOMNodeInserted', nodeInsertedHandler, false);

var timer = null;
var nodes = [];
function nodeInsertedHandler(e) {
  nodes.push(e.target);

  if (!timer) {
    timer = setTimeout(function() {
      /* 処理 */
      nodes = []; // スタック初期化
      timer = null; // タイマーを初期化
    }, 50);
  }
}

または

document.addEventListener('DOMNodeInserted', nodeInsertedHandler, false);

var timer;
var nodes = [];
function nodeInsertedHandler(e) {
  nodes.push(e.target);

  clearTimeout(timer);
  timer = setTimeout(function() {
    /* 処理 */
    nodes = [];
  }, 50);
}

後者の場合は、例えば連続してイベントが発生 (キーを押しっぱなしにしたりとか、マウスを動かすなど) してノードを追加するときに、最後のイベントが終わってから 50ms 時間が空けば処理を実行する。debouncing と呼ぶらしい。前者だと、イベントが連続して発生すると、途中に割り込んで処理を実行する。どちらが良いかはその時の状況で使い分けたらいい。


04:35

DOM Mutation 系のイベントは DOM 3 Events では deprecated となった。(だいぶ前の話だけど)

Warning! The MutationEvent interface was introduced in DOM Level 2 Events, but has not yet been completely and interoperably implemented across user agents. In addition, there have been critiques that the interface, as designed, introduces a performance and implementation challenge. A new specification is under development with the aim of addressing the use cases that mutation events solves, but in more performant manner. Thus, this specification describes mutation events for reference and completeness of legacy behavior, but deprecates the use of both the MutationEvent interface and the MutationNameEvent interface.

Document Object Model (DOM) Level 3 Events Specification

DOMMutation の代わりとして watchSelector (CSS セレクターを使うもの) と watchCharacterData (テキストノード用) というのが考えられているらしい。

IE の behavior: expression みたいな感じ。

こちらは非同期なので、Mutation Events の使用ケースを完全に置き換えることはできない。(まあ元々 Mutation Events が同期だったのがパフォーマンス的によくないということだったので)

上のページの下のほうにある、Replacing Traditional Mutation Events というところを見ると感じがつかめると思う。


DOM 4 Events を目指してるとか前に読んだので、しばらくは DOMMutation が使われると思う。

今まで listen だったところに watch というのがなんともアレだけど。


その他、最近になって DOMActivate と DOMFocusIn と DOMFocusOut も deprecated となった。(理由はこのへん)

I previously mentioned to you that the DOMActivate, DOMFocusIn, and 
DOMFocusOut were being considered for deprecation in DOM3 Events.  After 
looking into the matter closely and talking with various invested 
parties, I've now deprecated them in current drafts of the spec [1]. 
I've explained some of the rationale for this in the HCG [2].
XForms and Deprecating DOM* Events in DOM3 Events from Doug Schepers on 2010-02-01 (public-forms@w3.org from February 2010)

それだけ。

 |