gpt4 book ai didi

javascript - 如果在修改 DOM 后立即调用断开连接,则不会调用 MutationObserver 回调

转载 作者:行者123 更新时间:2023-11-29 22:03:48 26 4
gpt4 key购买 nike

我正在构建一个 undomanager,类似于 W3C undomanager,它还没有在各种浏览器中准备好。我实现了一个简单的事务调用,它在观察 DOM 的变化时调用回调,然后将必要的结构添加到数组中,该数组稍后可用于撤消(或重做)更改。

一个简单的例子:

function transact(callback){
/* Watch content area for mutations */
observer = new MutationObserver(function(){
/* TODO: collect mutations in here */
alert('Mutations observed');
});
observer.observe(document.getElementById('content'), {
attributes: false,
childList: true,
characterData: false,
subtree: false
});

/* Perform the callback */
callback();

/* Stop observing */
//observer.disconnect();
setTimeout(function(){ observer.disconnect();}, 1);

}

要使用它:

transact(function(){
var p = document.createElement('p');
p.innerHTML = 'Hello';
document.getElementById('content').appendChild(p);
});

如果我立即调用 observer.disconnect(),变异观察器永远不会到达 alert 调用,但如果我使用 setTimeout,它工作正常。

我非常乐意接受 setTimeout 调用,唯一的问题似乎是对于较大的更改,您必须将断开连接延迟多达 800 毫秒。

就好像断开连接发生在 DOM 更改实际完成之前,因此没有检测到任何东西。

这在 Firefox 25 和 Chrome 32 中都会发生。

我想了一秒钟,因为 observer 是一个局部变量,也许它很快就超出了范围,但是将它更改为全局变量并没有帮助。我必须延迟对 disconnect() 的调用,让 DOM 有机会 catch 它。

这是浏览器错误吗?有没有更好的方法在 DOM 再次准备好后立即调用 disconnect()

最佳答案

MutationObservers are async by specfication ,因为它们会在调用您的回调函数之前等待当前堆栈为空。这很有用,因此不会在每次更改 DOM 时调用回调,而是仅在完成所有更改后调用。 See how are MutationObserver callbacks fired?

如果您查看规范链接,您会注意到在 MutationEvent 之前涉及的步骤是:

  • MutationObserver 收到突变通知
  • 将突变追加到自上次事件以来的当前突变集/takeRecords
  • 在当前堆栈为空后调用回调函数(这就是为什么您的代码在设置超时后按预期工作的原因 - setTimeout 将在超时和堆栈清空后调用该函数)
  • 清空记录队列,继续观察

更新 抱歉,为了解决您的实际问题,我认为这可能与 MutationObserver 回调中的 alert 有关。处理突变绝对不应该超过几毫秒,而且它绝对应该发生在 setTimeout 之前。无论如何,一个肯定有效的解决方案是在 MutationObserver 回调中添加一个队列处理器,而不是使用超时。

function transact(callback){
var queue = [], listener; //queue of callbacks to process whenever a MO event occurs
/* Watch content area for mutations */
var observer = new MutationObserver(function(){ //made observer local
/* TODO: collect mutations in here */
alert('Mutations observed');
while(listener = queue.shift()) listener();
});
observer.observe(document.getElementById('content'), {
attributes: false,
childList: true,
characterData: false,
subtree: false
});

/* Perform the callback */
callback();

/* Stop observing */
//observer.disconnect();
queue.push(observer.disconnect.bind(observer));

}

关于javascript - 如果在修改 DOM 后立即调用断开连接,则不会调用 MutationObserver 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22096340/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com