为什么 MutationObserver 没有检测到随机点之后的节点?

问题描述 投票:0回答:1

我正在构建一个

Tampermonkey
用户脚本。我的实际脚本要复杂得多,但我可以通过以下示例进行重现。

我的脚本需要在黑客新闻网站上运行。

例如本页:

https://news.ycombinator.com/item?id=39778570

他们的 html 有

.athing
类,其中包含每个评论。对于每个这样的课程,我需要执行某个任务(与这个问题无关)。我正在使用
MutationObserver
来观察用户脚本中的这些节点:

我的用户脚本是这样的:

// ==UserScript==
// @name         HN
// @namespace    https://news.ycombinator.com/*
// @version      2024-02-02
// @description  For Hacker News
// @author       Bobby
// @match        https://news.ycombinator.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==


const recordObserver = new MutationObserver((mutations, observer) => {

    mutations.forEach(m => {

        if (m.type === "childList" && m.addedNodes) {
            m.addedNodes.forEach(target => {

                if (target.nodeType == Node.ELEMENT_NODE) {

                    target.querySelectorAll(`.athing:not([read_123])`).forEach (element=> {

                        element.setAttribute(`read_123`, true);

                        element.style.background = '#00FF0055';

                        console.log(element.id);
                    });
                }


            });
        }
    });
});

recordObserver.observe(document, {
    attributes: false,
    childList: true,
    characterData: false,
    subtree: true
});

请注意,一旦检测到,我的脚本就会更改该元素的背景颜色。

这在某种程度上似乎工作得很好。

它在随机节点上随机停止工作。此屏幕截图显示了问题:

注意它是如何检测的,直到出现注释

Yoga is great but only really supports flexbox. For.....
,之后它停止检测并停止在控制台中打印
id

如果我再次访问同一页面,它会停在不同的节点。

我无法确定到底是什么导致了这个问题。任何帮助将不胜感激。

请注意,此问题并非特定于

Tampermonkey
。我的实际问题发生在 iOS WKWebView 上,其中用户插入的脚本显示了相同的问题。我可以通过这种方式在桌面上重现此内容。

javascript jquery-selectors tampermonkey userscripts mutation-observers
1个回答
0
投票

MutationObserver 回调是异步的,因此以用户身份加载脚本加上希望它会在从原始页面源加载 DOM 时触发并不是一个完美的想法。例如,整个项目在 Firefox 中就行不通。

这里我更详细地解释了:为什么突变观察者是用微任务队列而不是宏任务队列处理的?

为了在 Chrome 中缓解这一问题,请尝试使回调尽可能短,以便赶上加载页面:



// ==UserScript==
// @name         HN
// @namespace    https://news.ycombinator.com/*
// @version      2024-02-02
// @description  For Hacker News
// @author       Bobby
// @match        https://news.ycombinator.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

const mutations = [];
let timeout;
const recordObserver = new MutationObserver(ms => (mutations.push(...ms), clearTimeout(timeout), timeout = setTimeout(processMutations)));

function processMutations(){
    mutations.forEach(m => {
        if (m.type === "childList" && m.addedNodes) {
            m.addedNodes.forEach(target => {

                if (target.nodeType == Node.ELEMENT_NODE) {

                    target.querySelectorAll(`.athing:not([read_123])`).forEach (element=> {

                        element.setAttribute(`read_123`, true);

                        element.style.background = '#00FF0055';

                        console.log(element.id);
                    });
                }


            });
        }
    });
}

recordObserver.observe(document, {
    attributes: false,
    childList: true,
    characterData: false,
    subtree: true
});
© www.soinside.com 2019 - 2024. All rights reserved.