有时突变观察者回调不会在我期望的时候触发。
如果我在开发人员工具控制台中运行此代码:
// 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]
没有记录到控制台。
什么会导致 Mutation Observer 无法在推特上运行?
mutations: [MutationRecord]
不登录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"));
例子
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)
我能够在这些特定情况下重现:
其他轶事:
takeRecord()
按预期工作。就像里面一样,它充满了变异记录。queueMicrotask(<cb>)
将您的工作与突变观察者回调分离并不能解决问题。setTimout(<cb>, 0)
确实解决了这个问题。因此,如果您遇到与我相同的问题,解决方法是将您的突变观察者回调包装在
setTimeout()
中,如下所示...
new MutationObserver(() => setTimeout(myHandler, 0));
老实说,我不太愿意将此称为答案。我相信这里的 Chromium 中存在一个 heisen-bug。如果您从不打开 Dev Tools,则此解决方法是多余的。
这个答案与 mayfield 的回应相吻合,这非常好。我同意这是一个 Chromium Devtools 错误,可以通过他在回答中提到的步骤重现。 setTimeout() 似乎可以(尽管不一致)缓解这种情况。我想知道这个错误是否也会影响其他观察者......
我想避免重构大量代码,所以我想出了这个 hacky 解决方案,将本机 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');