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

设置Slow 3G时MutationObserver未触发的技术问题排查

问题背景

我希望在动态创建的Hero Image加载完成后,再延迟加载非必要脚本。

代码实现
"use strict";

import { siteNavHandler } from "./siteNavHandler.min.js";
import { buildHeroGallery } from "./buildHeroGallery2.min.js";
import { pageNavHandlerList } from "./pageNavList.min.js";
import { lazyLoadingCtaSection } from "./lazyLoadingCtaSection.min.js";

document.addEventListener("DOMContentLoaded", init, false);
function init() {
  siteNavHandler();
  DelayScriptLoading();
  buildHeroGallery(); // 该模块负责加载动态Hero Image
  pageNavHandlerList();
  lazyLoadingCtaSection();
}

function DelayScriptLoading() {
  const interval = setInterval(function () {
    if (document.querySelector("#heroImage0")) {
      console.log("Found! with polling");
      const img = document.querySelector("#heroImage0");
      img.addEventListener("onload", loadjs("polling event listener on load", img));
      clearInterval(interval);
    }
  }, 500);

  const target = document.getElementById("top");
  console.dir(target);

  function addHandler(records, observer) {
    for (const record of records) {
      for (const addedNode of record.addedNodes) {
        if (addedNode.id == "heroImage0") {
          console.log("MutationObserver triggered for " + `${addedNode.id}`);
          const img = addedNode.querySelector(".hero-gallery-img");
          img.addEventListener("onload", loadjs("MutationObserver event listener on load", img));
        }
        observer.disconnect();
      }
    }
  }

  const observerOptions = {
    childList: true,
    subtree: true,
  };

  const observer = new MutationObserver(addHandler);
  observer.observe(target, observerOptions);

  async function loadjs(param, img) {
    console.log("img has loaded and load JS function triggered using " + `${param}`);
    console.dir(img);
  }
}
问题现象

将Chrome浏览器开发者工具的网络节流设置为Slow 3G时,MutationObserver未触发,但轮询机制可正常触发;设置为Fast 3G或更高速率时,两者均能正常触发。

控制台输出
  • Slow 3G下:
controllerList.js:28 section#top.heroGalleryContainer
controllerList.js:20 Found! with polling
controllerList.js:52 img has loaded and load JS function triggered using polling event listener on load
controllerList.js:53 img#heroImage0.hero-gallery-img
  • Fast 3G及以上:
controllerList.js:28 section#top.heroGalleryContainer
controllerList.js:34 MutationObserver triggered for heroImage0
controllerList.js:52 img has loaded and load JS function triggered using MutationObserver event listener on load
controllerList.js:53 img.hero-gallery-img
controllerList.js:20 Found! with polling
controllerList.js:52 img has loaded and load JS function triggered using polling event listener on load
controllerList.js:53 div#heroImage0.hero-gallery-div.img--FadeIn
补充说明

使用script defer无法满足需求,因为需要脚本在动态Hero Image加载完成后再加载;async加载也不可行,因为不希望脚本在后台占用带宽,直到Hero Image加载完成。

核心问题

为什么Slow 3G下MutationObserver不触发?


原因分析与修复

根本原因

问题出在addHandler函数里的observer.disconnect()调用时机错误:
在Slow 3G环境下,buildHeroGallery创建DOM节点的过程可能是分批异步完成的,当第一个非heroImage0的节点被添加到#top容器时,循环会直接执行observer.disconnect(),导致Observer提前停止监听,后续真正的heroImage0节点添加时无法触发回调。
而在Fast 3G或更快的网络下,heroImage0可能是第一批被添加的节点,Observer在处理完目标节点后才断开,因此能正常工作。

附带问题

  1. 事件绑定错误:img.addEventListener("onload", loadjs(...))直接调用了loadjs,应该传递函数引用,且正确事件名是load而非onload。
  2. DOM选择容错:如果heroImage0本身就是img元素,addedNode.querySelector(".hero-gallery-img")会找不到元素。

修复代码

调整Observer断开时机,并修复事件绑定问题:

function addHandler(records, observer) {
  for (const record of records) {
    for (const addedNode of record.addedNodes) {
      if (addedNode.id == "heroImage0") {
        console.log("MutationObserver triggered for " + `${addedNode.id}`);
        // 兼容目标节点本身是img的情况
        const img = addedNode.querySelector(".hero-gallery-img") || addedNode;
        // 传递函数引用而非直接执行
        img.addEventListener("load", () => loadjs("MutationObserver event listener on load", img));
        // 找到目标节点后再断开监听
        observer.disconnect();
        return; // 退出循环避免多余操作
      }
    }
  }
}

同时修正轮询逻辑里的事件绑定:

const img = document.querySelector("#heroImage0");
img.addEventListener("load", () => loadjs("polling event listener on load", img));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:43:24