Когда запускаются обратные вызовы MutationObserver?

Я знаю, что обратные вызовы MutationObservers могут быть вызваны через некоторое время после изменения DOM. Но вопрос в том, каковы сроки этих обратных вызовов? Попадают ли обратные вызовы в очередь событий браузеров? Если да, то когда они встают в очередь?

Это обратные вызовы:

  • вызывается сразу после мутации DOM,
  • вызывается, как только завершается функция, управляющая DOM,
  • вызывается, как только стек вызовов пуст,
  • ставится в очередь сразу после мутации DOM,
  • ставится в очередь, как только завершается функция, управляющая DOM, или
  • как нибудь в другой раз?

Например, если выполняется следующий фрагмент кода (с заданным здесь setZeroTimeout):

var target = document.body;

new MutationObserver(function(mutations) {
  console.log('MutationObserver');
}).observe(target, {
  attributes: true,
  childList: true,
  characterData: true
});


// Post message
setZeroTimeout(function () { console.log('message event'); });
// DOM mutation
target.setAttribute("data-test", "value");

Следует ли печатать «MutationObserver» до «события сообщения» или после него? Или это определяется реализацией?

Я получаю «MutationObserver» перед «событием сообщения» на Chromium 26, хотя мутация DOM происходит после публикации сообщения. Возможно, это указывает на то, что обратные вызовы MutationObserver не используют очередь событий.

Я искал в Google спецификацию HTML, спецификацию DOM или документы по реализации браузера, но не нашел ничего, связанного с этим поведением.

Любое объяснение или документация о времени обратных вызовов MutationObservers, пожалуйста?


person FelisCatus    schedule 28.01.2013    source источник
comment
Я предполагаю, что если наблюдатели за мутациями используют очередь событий, совершенно неудивительно, что message event предшествует MutationObserver. Обработчик postMessage в setZeroTimeout запускает и запускает событие (которое добавляется в очередь событий), а затем вызов setAttribute отключает наблюдателя (и это, вероятно, также добавляет событие в очередь после события сообщения).   -  person apsillers    schedule 28.01.2013
comment
@apsillers Я получаю MutationObserver перед событием сообщения, а не наоборот.   -  person FelisCatus    schedule 28.01.2013
comment
Ах, моя ошибка. Тогда да, это указывает на то, что MutationObservers не используют очередь событий.   -  person apsillers    schedule 28.01.2013
comment
Это может быть дополнительно осложнено тем фактом, что события postMessage могут вести себя не так, как другие события, но я не уверен в этом на 100%.   -  person apsillers    schedule 28.01.2013
comment
@apsillers Предлагаете ли вы какие-либо другие асинхронные события, которые можно использовать для тестирования в этом вопросе?   -  person FelisCatus    schedule 28.01.2013
comment
@apsillers кажется правильным, они не используют очереди событий: dvcs.w3.org/hg/domcore/raw-file/tip/   -  person joseeight    schedule 21.02.2013
comment
@joseeight Но этот документ не определяет, КОГДА они вызываются. Вместо этого в нем говорится, что стандарт HTML определяет, как эта концепция интегрируется с остальной частью платформы, а также когда вызывается вызов.   -  person FelisCatus    schedule 21.02.2013


Ответы (2)


MutationObservers запускаются асинхронно, но «скоро», что означает, что они запускаются до других вещей в очереди, таких как макет, рисование или инициированные события.

Это улучшает потерю синхронности, потому что вам не нужно беспокоиться о мигании экрана или других плохих вещах, прежде чем ваш наблюдатель получит возможность отреагировать.

В примечаниях разработчиков они говорят о модели синхронизации «конец микрозадачи». Я согласен, что это плохо документировано.

person Scott Miles    schedule 08.04.2013
comment
Спасибо за ваше подробное объяснение! Я думаю, что мне следует подождать, пока модель будет исправлена ​​и задокументирована, прежде чем писать что-либо, основанное на предположении о порядке обратных вызовов. - person FelisCatus; 13.04.2013

Я собираюсь ответить на свой вопрос два года спустя в соответствии с обновленной спецификацией DOM от WHATWG.

Как показано в спецификации:

Чтобы поставить в очередь составную микрозадачу наблюдателя мутаций, выполните следующие действия:

  1. Если установлен флаг постановки в очередь составной микрозадачи наблюдателя мутаций, прекратите эти шаги.
  2. Установить флаг постановки в очередь составной микрозадачи наблюдателя мутаций.
  3. Поставьте в очередь составную микрозадачу, чтобы уведомить наблюдателей за мутациями.

При постановке в очередь составной микрозадачи создается ссылка на раздел спецификации HTML объяснение модели очереди микрозадач.

Таким образом, мы можем сделать вывод, что обратные вызовы MutationObserver запускаются как микрозадачи, которые действительно выполняются раньше, чем задачи очереди задач, как это предлагается ответом @Scott миль выше.

Для дальнейшего понимания цикла событий и модели обработки см. раздел "Цикл событий" спецификации HTML было бы идеально.

Лично я рад видеть, что MutationObserver являются частью стандарта и имеют хорошо документированную и последовательную модель синхронизации. Поскольку MutationObservers поддерживается в большинстве современных браузеров, я думаю, что сейчас они вполне пригодны для использования в производственной среде.

person FelisCatus    schedule 16.12.2015
comment
Спасибо за комментарии, @FelisCatus; Я использую MutationObserver для обнаружения изменений в приложении Angular SPA, и проблема в том, что эти обратные вызовы запускаются много раз для каждой навигации пользователя. Мне интересно, есть ли способ определить, когда это будет завершено, то есть когда DOM, наконец, загружен/изменен, и больше никаких изменений не произойдет, если пользователь не перейдет снова. - person David; 19.02.2016
comment
@david Вы не можете быть уверены, что больше не произойдет никаких изменений, поскольку эти наблюдатели могут продолжать стрелять, и в $timeout могут быть другие изменения и так далее. Однако я думаю, что вполне безопасно предположить, что DOM больше не будет изменяться, как только не будет ожидающих запросов AJAX И DOM не будет обновляться в течение 1 или 2 секунд. - person FelisCatus; 20.02.2016