0

I am building a Tampermonkey user script. My actual script is a lot more complex but I am able to reproduce with the following example.

My script needs to work on Hacker News website.

For example on this page:

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

Their html has .athing class which contains each comment. For each such class, I need to do a certain task (not relevant to this question). I am using MutationObserver to observe for those nodes in my user script:

My user script is this:

// ==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
});

Notice how once detected, my script changes the background color of that element.

This seems to work fine to a certain point.

It randomly stops working at random nodes. This screenshot shows the issue:

enter image description here

Notice how it detected until the comment Yoga is great but only really supports flexbox. For..... after which it stopped detecting and also stopped printing the id in console.

If I access the same page again, it stops at different node.

How can I pin point what exactly is causing this issue?

Note that this issue isn't specific to Tampermonkey. My actual issue is occurring on iOS WKWebView where a user inserted script shows the same issue. I am able to reproduce this on desktop this way.

1 Answer 1

0

MutationObserver callbacks are async so loading the script as a user one plus hoping it will trigger on loading DOM from the original page source is not a perfect idea. The whole venture doesn't work in Firefox for example.

Here I've explained in more details: Why mutation observer is processed with microtask queue and not macrotask queue?

To mitigate in Chrome try to make your callback as short as possible so you would catch up with the loading page:



// ==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
});
6
  • Where can I find docs on "MutationObserver callbacks are async"? It doesn't mention on developer.mozilla.org/en-US/docs/Web/API/MutationObserver Commented Mar 22 at 20:08
  • @sudoExclamationExclamation it's strange there's no mention of microtask, but i remember when i first learned about MutationObserver that was clearly mentioned. most probably it was MDN. i don't know there's no clear mention of that now Commented Mar 22 at 22:02
  • If this is the case, does that mean that I cannot rely on MutationObserver to get the appended nodes in order? For example, I can't rely on it to get incoming chat messages in the incoming order? Commented Mar 23 at 1:27
  • @sudoExclamationExclamation you are trying to watch page content returned from the server in your case? that's not mutations imho Commented Mar 23 at 8:59
  • No, by incoming chat messages, I meant messages being inserted into the page using HTML. Like imagine the YouTube super chat feature where super chats are inserted into the page with their various coloured backgrounds. I need to do something when such mutations occur. Commented Mar 23 at 20:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.