MutationObserver/Mutation Events は孫DOMへの操作も検知するのか

MutationObserver/Mutation Events は、孫DOMへの操作も検知するのだろうか。Chrome48.0.2564.103 とFirefox44.0.2で検証した。

※ざっくりした調査なのでご参考までに。

結論

MutationObserverは仕様にsubtreeオプションがあり、ChromeFirefoxもこれを実装している。問題なく検知する。

Mutation Events (廃止された仕様) は、Chromeで一部検知しない。Firefoxでは検知できた。

Mutation Events

廃止された仕様。使ってはいけない。Mutation events - Web developer guides | MDN

とりあえず、この3つだけを調査の対象とする。全イベント一覧はこちら

  • DOMAttrModified
  • DOMNodeInserted
  • DOMNodeRemoved

HTML

<body>
  <div>
    <div id="descendant"></div>
  </div>
  <script src="./main.js"></script>
</body>

JavaScript

'use strict';

/*
 * Mutation Events を document.body に登録する
 */
[ 'DOMAttrModified', 'DOMNodeInserted', 'DOMNodeRemoved' ]
.forEach(type => {
  document.body.addEventListener(type, e => {
    console.log('=======', e.type);
  });
});

/*
 * 孫DOMに対し、操作を加えてみる
 */
test();

function test() {
  let el = document.getElementById('descendant');
  let textNode = document.createTextNode('boooom');
  el.setAttribute('boom', 'boom');
  el.appendChild(textNode);
  setTimeout(() => el.removeChild(textNode), 800);
}

実行結果

Firefox

全てのイベントがdocument.bodyまで伝播している。

======= DOMAttrModified a.js:10:5
======= DOMNodeInserted a.js:10:5
======= DOMNodeRemoved a.js:10:5

Chrome

DOMAttrModifiedだけdocument.bodyに来ない。

======= DOMNodeInserted a.js:10 
======= DOMNodeRemoved a.js:10 

MutationObserver

MutationObserver - Web API インターフェイス | MDN

結果として、FirefoxChromeも仕様通り機能した。平和平和。

JavaScript

HTMLと、検証用test()関数は上記と同じ。MutationObserverのコードをこうした。

/*
 * Mutation Observerを登録。
 */

let mo = new MutationObserver(mutationRecords => {
  console.log('=======', mutationRecords.map(r => r.type));
});
mo.observe(document.body, {
  childList: true,
  attributes: true,
  characterData: true,
  subtree: true, /* ここポイント */
  attributeOldValue: true,
  characterDataOldValue: true
});

Firefox

======= Array [ "attributes", "childList" ] a.js:19:3
======= Array [ "childList", "characterData", "characterData" ] a.js:19:3
======= Array [ "childList" ] a.js:19:3

Chrome

======= ["attributes", "childList"] a.js:19
======= ["childList", "characterData", "characterData"] a.js:19
======= ["childList"] a.js:19

同じ結果を返していることが分かる。

参考にした記事

非推奨になった Mutation events を Mutation Observers に置き換えよう - ログろいど