【问题标题】:When are MutationObserver callbacks fired?何时触发 MutationObserver 回调?
【发布时间】:2013-01-11 22:39:15
【问题描述】:

我知道 MutationObservers 回调可能会在 DOM 更改后的某个时间被调用。但问题是:这些回调的时机是什么? 回调是否进入浏览器的事件队列?如果是,他们什么时候进入队列?

是回调:

  • 在 DOM 突变发生后立即调用,
  • 在操作 DOM 的函数完成后立即调用,
  • 调用堆栈为空时立即调用,
  • 在 DOM 突变发生后立即排队,
  • 在操作 DOM 的函数完成后立即入队,或者
  • 在其他时间?

例如,如果执行以下代码(使用setZeroTimeout defined here):

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”应该打印在“消息事件”之前还是之后? 还是实现定义的?

我在 Chromium 26 上的“消息事件”之前获得了“MutationObserver”,尽管 DOM 突变是在消息发布之后。也许这表明 MutationObserver 回调使用事件队列。

我搜索了 HTML 规范、DOM 规范或浏览器实现文档,但没有找到与此行为相关的任何内容。

请提供关于 MutationObservers 回调时间的任何解释或文档?

【问题讨论】:

  • 我的猜测是,如果突变观察者使用事件队列,message event 出现在MutationObserver 之前就不足为奇了。 setZeroTimeout 中的 postMessage 处理程序触发并触发一个事件(添加到事件队列中),然后 setAttribute 调用触发观察者(这可能还会在消息事件后面添加一个事件到队列中)。
  • @apsillers 我在“消息事件”之前得到“MutationObserver”,而不是相反。
  • 啊,我的错。那么,是的,这似乎表明MutationObservers 不使用事件队列。
  • 这可能会因为postMessage 事件的行为可能与其他事件不同这一事实而变得更加复杂,但我不能 100% 确定这一点。
  • @joseeight 但是本文档没有定义它们何时被“调用”。相反,它说“HTML 标准定义了这个概念如何与平台的其余部分集成以及何时调用调用。”

标签: javascript dom browser dom4


【解决方案1】:

两年后我会根据updated DOM spec from WHATWG回答我自己的问题。

如规范所示:

要将突变观察者复合微任务排队,请运行以下步骤:

  1. 如果设置了变异观察者复合微任务队列标志,则终止这些步骤。
  2. 设置突变观察者复合微任务队列标志。
  3. 将复合微任务排队以通知突变观察者。

虽然“对复合微任务进行排队”链接到 a section in the HTML spec 解释微任务队列模型。

因此,我们可以得出结论,MutationObserver 回调作为微任务被触发,这确实比the answer of @Scott Miles above 建议的任务队列任务更快。

为了进一步了解事件循环和处理模型,HTML 规范的the Event Loop section 将是完美的。

就我个人而言,我很高兴看到MutationObservers 是标准的一部分,并且有一个有据可查且一致的时序模型。对于MutationObservers supported in most modern browsers,我认为它们现在可以用于生产。

【讨论】:

  • 感谢 cmets,@FelisCatus;我正在使用 MutationObserver 来检测 Angular SPA 应用程序中的更改,问题是每次用户导航都会多次触发这些回调。我想知道是否有办法检测何时完成,即 DOM 何时最终加载/更改,除非用户再次导航,否则不会发生更多更改。
  • @david 你不能确定不会再发生变化,因为这些观察者可以继续开火,$timeout 中可能会有更多变化等等。但是,我认为只要没有挂起的 AJAX 请求并且 DOM 没有更新 1 或 2 秒,DOM 将不再更改是非常安全的。
【解决方案2】:

MutationObservers 被异步触发但“很快”,这意味着它们在队列中的其他事物之前触发,例如布局、绘制或触发事件。

这可以改善同步的损失,因为在观察者有机会做出反应之前,您不必担心屏幕闪烁或其他坏事发生。

在开发人员说明中,他们谈到了“微任务结束”时序模型。我同意这没有很好的记录。

【讨论】:

  • 感谢您的详细解释!我认为在基于回调顺序的假设编写任何内容之前,我应该等待模型修复和记录。
猜你喜欢
  • 2016-01-17
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-24
  • 2015-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多