有时,当我期望它触发时,突变观察者回调不会触发。
如果我在开发人员工具控制台运行以下代码:
// callback for mutations observer
callbackForAllChanges = function (mutationsList, observer) {
console.log("mutations: ", mutationsList);
};
// create mutation observer
allChanges = new MutationObserver(callbackForAllChanges);
// attach mutation observer to document
allChanges.observe(document, {
childList: true,
subtree:true
});
// create new child
document.body.appendChild(document.createElement("div"));
我希望当我创建一个新的子线程时,回调函数会被触发。但有时会,有时不会。
当我在stackoverflow上运行devtools控制台的代码时,它可以工作:我看到mutations: [MutationRecord]
记录到控制台。
当我去twitter并在devtools控制台运行上述代码时,它似乎不起作用:mutations: [MutationRecord]
没有记录到控制台。
什么会导致突变观察者不能在twitter上工作?
重新创建issue
- 去twitter 打开devtools控制台
- 粘贴以上代码,看到
mutations: [MutationRecord]
不记录
更新2
推特又不能用了。我还发现,如果我添加一个突变观察者到我创建的div,这也不起作用,但在其他网站上工作。const newDiv = document.createElement('div')
newDiv.setAttribute('id','newDiv')
// callback for mutations observer
callbackForAllChanges = function (mutationsList, observer) {
console.log("mutations: ", mutationsList);
};
// create mutation observer
allChanges = new MutationObserver(callbackForAllChanges);
// attach mutation observer to document
allChanges.observe(newDiv, {
childList: true,
subtree:true
});
// create new child
newDiv.appendChild(document.createElement("div"));
3
更新- 变异观察者在隐身状态下没有停止工作
- 关闭所有扩展不修复突变观察者当它不工作
- 退出和重启chrome似乎修复停止工作时的突变观察者
- 清除cookies不能解决问题
更新4
它可能与无限循环有关,在无限循环中,当观察到突变时,添加一个节点。这会导致观察到一个突变(新添加的节点)。等等......
例子const callbackForAllChanges = function (mutationsList, observer) {
if (mutationsList.find((record) => record.type === "childList")) {
document.body.appendChild(document.createElement("div"));
}
};
我认为如果这种情况发生,它可能会触发突变工作停止工作。
我正面临着同样的问题,现在我修补了回调使用循环和检查是否有一些更改手工。
setInterval(() => {
const recs = allChanges.takeRecords()
if (recs.length === ) return
yourcallback(recs)
}, 30)
我可以在这些特定的情况下复制这个:
- Dev Tools是打开的
- 代码中有断点或调试器语句在MutationObserver回调
- 第一次加载页面,页面在断点处成功停止
- 当仍然时重新加载页面在断点
- MutationObserver回调永远不会再运行任何未来的页面重载
- 关闭页面和任何其他网站,并开始一个新的选项卡(即。创建新页面进程)将状态重置回第一步
其他轶事:
- 我尝试了一些旧版本的chromium(大约v97),有趣的是,我发现如果试图从突变观察者回调断点重新加载页面,其中许多会崩溃。
- 存储对MutationObserver的引用并使用
takeRecord()
按预期工作。因为,它充满了突变记录。 - 使用
queueMicrotask(<cb>)
将您的工作与突变观察者回调解耦并不能解决问题。 - 使用
setTimout(<cb>, 0)
确实解决了这个问题。
因此,如果您遇到与我相同的问题,那么解决方法将是在setTimeout()
中包装您的突变观察者回调,如下所示…
new MutationObserver(() => setTimeout(myHandler, 0));
老实说,我觉得把这个叫做答案不太舒服。我相信Chromium中有一个海森堡bug。如果你从不打开开发工具,这个解决方法是多余的。
这个回答与mayfield的回答相吻合,mayfield的回答非常好。我同意这是一个Chromium Devtools的bug,可以通过他在回答中提到的步骤重现。setTimeout()似乎可以减轻这种情况(尽管不一致)。我想知道这个bug是否也会影响其他观察者…
我想避免重构大量代码,所以我想出了这个hack的解决方案,将本机MutationObserver类包装在您自己的匿名类中(需要在实例化任何观察者之前运行):
function fixObserver(name) {
let original=window[name];
window[name]=class {
constructor (cb) {
return new original((...params) => {
setTimeout(() => cb(...params));
});
}
};
}
fixObserver('MutationObserver');
fixObserver('ResizeObserver');
fixObserver('IntersectionObserver');