javascript 什么会导致整个文档和子树上的Mutation Observer在添加子对象时不触发?

ki1q1bka  于 2023-03-28  发布在  Java
关注(0)|答案(3)|浏览(130)

有时候,变异观察者回调函数并没有像我期望的那样被触发。
如果我在开发人员工具控制台中运行以下代码:

// 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无法在Twitter上运行?

重新创建问题

1.转到twitter
1.打开devtools控制台
1.粘贴上面的代码并查看mutations: [MutationRecord] does not log

更新

现在它在twitter上对我有效,所以看起来断断续续。

更新2

它在twitter上又停止工作了。我还发现,如果我向我创建的div添加一个突变观察器,它也不起作用,但在其他网站上起作用。

更新3

  • 变异观察者一直在隐姓埋名
  • 关闭所有扩展 * 不会修复 * 突变观察器不工作时的问题
  • 退出并重新启动chrome似乎可以修复当它停止工作时的突变观察器
  • 清除cookie * 并不能 * 解决问题

更新4

它可能与一个无限循环有关,当观察到一个突变时,会添加一个节点。这会导致观察到一个突变(新添加的节点)。依此类推......
示例

const callbackForAllChanges = function (mutationsList, observer) {
    if (mutationsList.find((record) => record.type === "childList")) {      
  document.body.appendChild(document.createElement("div"));
    }
  };

我认为如果发生这种情况,它可能会触发突变工作停止工作。

voj3qocg

voj3qocg1#

我也面临着同样的问题,现在我使用一个循环来修补回调,并检查是否手动进行了一些更改。

setInterval(() => {
  const recs = allChanges.takeRecords()
  if (recs.length === ) return
  yourcallback(recs)
}, 30)
gcuhipw9

gcuhipw92#

我可以在这些特定的情况下重现这个:
1.开发工具已打开
1.代码在MutationObserver回调中具有断点或调试器语句
1.第一次加载页,并且页在断点处成功停止
1.当在断点中时重新加载页面

  1. MutationObserver回调将不再为任何未来的页面重新加载运行
    1.关闭网页和任何其他网站,并启动一个新的标签(即创建新的网页进程)重置状态回到第一步
    其他轶事:
  • 我在一些较旧的chromium版本(大约是v97)上尝试了这个方法,有趣的是,我发现如果试图从一个mutation observer回调断点重新加载页面,其中许多都会崩溃。
  • 存储一个对MutationObserver的引用并使用takeRecord()可以正常工作。
  • 使用queueMicrotask(<cb>)将您的工作与突变观察器回调解耦并不能解决这个问题。
  • 使用setTimout(<cb>, 0)可以解决问题。

因此,如果您遇到了与我相同的问题,解决方法是将您的mutation observer回调 Package 在setTimeout()中,如下所示......

new MutationObserver(() => setTimeout(myHandler, 0));

老实说,我不太愿意把这个叫做答案。我相信Chromium中有一个海森bug。如果你从来没有打开过开发工具,这个解决方案是多余的。

ilmyapht

ilmyapht3#

这个答案与response from mayfield非常吻合。我同意这是一个Chromium Devtools的bug,可以通过他在回答中提到的步骤重现。setTimeout()似乎可以缓解这个问题(尽管不一致)。我想知道这个bug是否也会影响其他观察者...
我想避免重构大量代码,所以我想出了这个黑客解决方案,将本地MutationObserver类 Package 在自己的匿名类中(需要在示例化任何观察者之前运行):

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');

相关问题