MutationObserverのレコードとsubtreeの通知
MutationObserverは変更ごとにコールバックを約束せず、レコードをまとめてマイクロタスクで通知します。subtreeとオプションの意味を整理します。
発行・訂正窓口:infostoa · 編集基準
この記事の個別の執筆者・専門査読者の情報は提供されていません。
DOMの変更はMutationRecordとして記録され、待機中のobserverはマイクロタスクで通知されます。個々の変更ごとにコールバックが一度ずつ呼ばれるとは限りません。DOM標準はキューと通知手順を定め、MDNのobserve()解説はオプションを説明します。
概念図であり、ブラウザーでの実行結果ではありません。
オプションで監視対象を決める
observer.observe(target, options)ではchildList、attributes、characterDataから必要な変更種別を選びます。subtree:trueは子孫にも監視を広げます。有効な変更種別を指定せずsubtreeだけを使うと、設定エラーになることがあります。一つのobserverで複数の対象を監視でき、同じ対象に再度observeすると設定が更新されます。
レコードはまとめて届く
標準は変更observerのマイクロタスクをキューに入れ、すでに待機中なら重複して予約しません。通知時にキューから取り出されたレコード群がコールバックに渡ります。変更数と呼び出し回数は一対一ではありません。コールバック内のDOM変更は新たなレコードを生み、後続通知を予約できます。フレーム単位や一定時間内の通知は保証されません。
子孫を削除した直後
subtree監視中に子孫を削除しても、削除レコードが通知されるまでは、その分離した部分木の変更が捕捉される場合があります。標準はこの間、一時的な登録observerを使い、通知時に整理します。削除後も永久に監視されるという意味ではありません。そのノードへ別のobserverを直接登録している場合は別です。
必要なレコードに絞る
実際に必要なattributes、characterData、childListだけを選び、attributeFilterで属性を絞ります。attributeOldValueは以前の値が必要な場合に使います。attributes:falseとの組み合わせは矛盾し、旧値オプションやフィルターの指定によって属性監視が有効になる場合があります。characterDataOldValueも同様に確認します。不要になったらdisconnect()で監視を切り、未配信レコードが必要なら先にtakeRecords()で取得します。毎回DOM全体を再走査せず、レコードの対象と種別を使って後続処理を絞りましょう。
オプションと各レコードを確認する
リストの子ノード追加・削除だけならobserver.observe(list, {childList: true, subtree: true})のように明示します。属性変更と以前の値が必要ならattributes: trueとattributeOldValue: trueを指定し、attributeFilter: ['class', 'aria-expanded']で絞ります。filterやoldValueの指定がattributes省略時の有効化に関わるため、意図を明記するとレビューしやすくなります。attributes: falseとattributeOldValue: trueのような矛盾は例外になります。characterDataOldValueとcharacterDataも同様に整合させます。MDNのobserveオプションは既定値と無効な組み合わせを説明します。
MutationRecordの説明ではtype、target、addedNodes、removedNodes、attributeName、oldValueなどを確認できます。record.typeに応じて必要なtargetだけ処理し、通知のたびに大きな部分木全体を比較しないようにします。レコードは変更通知であり、DOM全体の変更前後スナップショットではありません。oldValueを要求していなければ以前の値をレコードから復元できず、コールバック時点で参照ノードがさらに変化していることもあります。
状態を切り替える直前に未配信レコードを同期的に処理する必要があればtakeRecords()でキューを取り出して空にできます。disconnect()は監視を止めますが、未処理の変更をアプリ状態へ自動反映するものではありません。破棄前にtakeRecords()の内容を処理するか捨てるか決めます。逆に、コールバックへ届いたレコードを処理中に同じ変更を再取得すると二重反映につながる場合があります。
専門家の見解: 通知と状態を分ける
MDN contributorsは、削除された部分木も削除レコードが通知されるまでは監視対象になり得ると説明しています。実務ではMutationObserverを永続的な状態保存先とみなさず、コールバックのレコードと現在のDOMを区別します。アプリの基準状態を別に保つと、削除や再接続の境界で変更を欠落・二重反映する危険を減らせます。