MutationObserverは、DOMが変化したときにコールバック関数を実行する。コールバックの引数は2つで、第一引数がMutationRecordオブジェクトの入った配列、第二引数はコールバックを実行しているインスタンス。
この第一引数の配列をループで回すという使い方をよくするのだが、disconnect()してるのにループが止まらないという不具合に遭遇した。
いきなり結論を書いてしまうと、disconnect()した回でループを止めるには、breakやreturnでループを抜ける必要がある。disconnect()はループを抜けるメソッドじゃないのだから、止まらなくても当たり前ではあるのだが、じゃあdisconnect()って何なんだ。DOMの監視をやめるメソッドじゃないのか。
MDNの該当ページを確認してみると、
すでに検知されているものの、まだオブザーバーに報告されていない変更の通知は、すべて破棄されます。
と書いてある。自分の認識と相違なさそうな気がするんだけどなあ。それに、こういう仕様ならばループは止まってもよさそうである。
でも「検知」とか「報告」というワードがちと臭い感じもするな。とりあえず、第一引数の配列のlength値を観察してみた。
最初に書いたように、DOMが変化したときにコールバックが実行されているわけなので、ジェネレーターみたいにいっこいっこ処理してるイメージでいたのだけれど、なんか違うっぽい。要素数がバラバラなのだ。1つだったり、50とかあったりする。
なるほど。そりゃあdisconnect()しても止まらないわけだ。配列の要素が残ってるからな。
コールバック実行中に待たされてるMutationRecordを、次のコールバックでまとめて引き渡してる感じなんだろうか。disconnect()が発動すると、次のコールバックが実行されなくなり、待たされてるMutationRecordも必然的に破棄されると。でも現在処理中のループは最後の要素まで回る。
これ知らなかったのに今までよく不具合が起きなかったな……。
あと、ループで回さないと漏れが出るのではないかと心配していたのだが、そんなアホなこと気にする必要ないんだな。むしろループを使わない処理を真っ先に考えるべきだわ。
0 件のコメント:
コメントを投稿