You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tampermonkey脚本中MutationObserver在Firefox下始终遗漏首个节点

Hacker News Tampermonkey脚本Firefox遗漏首个节点问题

问题描述

编写了如下Tampermonkey自定义脚本,用于标记Hacker News的标题节点:

// ==UserScript==
// @name         Hacker News
// @namespace    https://news.ycombinator.com/*
// @version      2024-02-02
// @description  try to take over the world!
// @author       You
// @match        https://news.ycombinator.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant        none
// ==/UserScript==

var observer = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    if (mutation.type === "childList" && mutation.addedNodes && mutation.addedNodes.length > 0 && mutation.addedNodes[0].nodeType == Node.ELEMENT_NODE) {
      Array.from(mutation.addedNodes[0].querySelectorAll('span.titleline')).forEach (element=> {
        console.log(`Matched: ${element.innerText}`);
        element.style.background = 'yellow';
        if (window.webkit) {
            window.webkit.messageHandlers.gotData.postMessage(element.innerText);
        }
      });
    }
  });
});

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

该脚本在Chrome中运行正常,但在Firefox中始终遗漏页面的首个标题节点。已将脚本的Run at设置为document-start,按预期此时首个节点不应已加入文档,但实际页面重载时,首个节点会在MutationObserver开始监测前加载,从而躲过监测。Hacker News页面为服务端渲染,需要明确Firefox下的特殊情况及解决办法。

原因分析

  • Firefox对document-start时机的处理差异:Chrome中document-start脚本会在文档开始解析前执行,此时DOM完全为空;但Firefox在处理服务端渲染的HTML流时,会提前解析并构建部分初始DOM节点,这部分节点的插入事件会发生在document-start脚本执行之前,导致MutationObserver无法捕捉到。
  • 服务端渲染页面的DOM构建特性:Hacker News的页面是纯服务端生成的完整HTML,Firefox在接收HTML内容时会采用流式解析,逐步将节点插入DOM树。当document-start脚本执行时,首个标题节点可能已经被插入到文档中,而此时Observer还未启动,自然无法监测到这个节点的添加。

解决方案

最可靠的解决方式是在启动MutationObserver后,主动扫描一次当前已存在的所有标题节点,补上对初始DOM中节点的处理,避免遗漏。修改后的脚本如下:

// ==UserScript==
// @name         Hacker News
// @namespace    https://news.ycombinator.com/*
// @version      2024-02-02
// @description  try to take over the world!
// @author       You
// @match        https://news.ycombinator.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant        none
// ==/UserScript==

var observer = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    if (mutation.type === "childList" && mutation.addedNodes && mutation.addedNodes.length > 0 && mutation.addedNodes[0].nodeType == Node.ELEMENT_NODE) {
      Array.from(mutation.addedNodes[0].querySelectorAll('span.titleline')).forEach (element=> {
        console.log(`Matched: ${element.innerText}`);
        element.style.background = 'yellow';
        if (window.webkit) {
            window.webkit.messageHandlers.gotData.postMessage(element.innerText);
        }
      });
    }
  });
});

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

// 主动处理已存在的初始标题节点
Array.from(document.querySelectorAll('span.titleline')).forEach(element => {
  console.log(`Matched (initial): ${element.innerText}`);
  element.style.background = 'yellow';
  if (window.webkit) {
      window.webkit.messageHandlers.gotData.postMessage(element.innerText);
  }
});

这种方式不管浏览器对document-start的处理差异如何,都能覆盖初始DOM中的节点,同时保留MutationObserver对后续动态添加节点的监测能力。

内容的提问来源于stack exchange,提问作者sudoExclamationExclamation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:34:59