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

如何判断AJAX网站的所有资源(HTML、CSS等)已完全加载?

纯JavaScript实现AJAX驱动网站的全资源加载完成检测

我明白你的痛点——依赖AJAX动态加载资源的网站,普通的window.onload根本没法准确判断所有资源是否加载完成,而且还不能用jQuery。下面给你一套纯JavaScript的解决方案,覆盖你提到的两个疑问,帮你搞定这个问题:

核心思路

要实现这个需求,我们需要做两件关键的事:

  1. 拦截所有XMLHttpRequest请求:捕获AJAX返回的内容,从中提取出需要加载的资源(比如图片、脚本、样式表)。
  2. 监控所有资源的加载状态:包括页面初始渲染的资源,以及AJAX动态插入到页面的资源,维护一个待加载资源列表,当列表为空时就表示所有资源加载完成。

解决你的疑问

先直接回应你提到的两个问题:

  • 疑问a:通过AJAX加载的图片完全可以被跟踪——不管是AJAX返回的HTML片段里的img标签,还是通过AJAX获取图片URL后动态创建的img元素,我们都能捕捉到并监控它们的加载状态。
  • 疑问b:具体跟踪方法分为「拦截AJAX提取资源」和「监控DOM动态元素」两部分,下面会给出完整代码示例。

完整实现代码

// 用于存储待加载的资源标识(URL或元素唯一标识)
const pendingResources = new Set();

// 资源加载完成后的回调函数,你可以在这里做自己的逻辑
function onAllResourcesLoaded() {
    console.log("所有资源已完全加载!");
    // 这里添加你的业务逻辑,比如隐藏加载动画、执行后续操作
}

// 检查是否所有资源都已加载完成
function checkAllLoaded() {
    if (pendingResources.size === 0) {
        // 用setTimeout确保DOM更新完成
        setTimeout(onAllResourcesLoaded, 0);
    }
}

// 监控单个资源的加载状态
function monitorResource(resource) {
    if (!resource) return;

    // 如果是图片资源(URL或img元素)
    if (typeof resource === 'string' && /\.(png|jpg|jpeg|gif|webp|svg)$/i.test(resource)) {
        const img = new Image();
        pendingResources.add(resource);
        img.onload = img.onerror = () => {
            pendingResources.delete(resource);
            checkAllLoaded();
        };
        img.src = resource;
        return;
    }

    // 如果是脚本元素
    if (resource.tagName === 'SCRIPT') {
        const scriptUrl = resource.src || resource.innerHTML;
        pendingResources.add(scriptUrl);
        resource.onload = resource.onerror = () => {
            pendingResources.delete(scriptUrl);
            checkAllLoaded();
        };
        return;
    }

    // 如果是样式表元素
    if (resource.tagName === 'LINK' && resource.rel === 'stylesheet') {
        const styleUrl = resource.href;
        pendingResources.add(styleUrl);
        resource.onload = resource.onerror = () => {
            pendingResources.delete(styleUrl);
            checkAllLoaded();
        };
        return;
    }
}

// 从HTML字符串中提取所有资源URL
function extractResourcesFromHtml(html) {
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = html;
    const resources = [];

    // 提取图片
    const imgs = tempDiv.querySelectorAll('img');
    imgs.forEach(img => img.src && resources.push(img.src));

    // 提取脚本
    const scripts = tempDiv.querySelectorAll('script');
    scripts.forEach(script => script.src && resources.push(script.src));

    // 提取样式表
    const links = tempDiv.querySelectorAll('link[rel="stylesheet"]');
    links.forEach(link => link.href && resources.push(link.href));

    return resources;
}

// 拦截XMLHttpRequest,监控AJAX请求返回的资源
const originalXHROpen = XMLHttpRequest.prototype.open;
const originalXHRSend = XMLHttpRequest.prototype.send;

XMLHttpRequest.prototype.open = function(method, url) {
    this._url = url;
    originalXHROpen.apply(this, arguments);
};

XMLHttpRequest.prototype.send = function() {
    this.addEventListener('load', () => {
        // 只处理HTML类型的响应(根据实际需求调整)
        if (this.responseType === '' || this.responseType === 'document' || this.getResponseHeader('Content-Type')?.includes('text/html')) {
            const resources = extractResourcesFromHtml(this.responseText);
            resources.forEach(resource => monitorResource(resource));
        }
    });
    originalXHRSend.apply(this, arguments);
};

// 监控DOM动态添加的元素(比如AJAX返回后插入到页面的元素)
const observer = new MutationObserver((mutations) => {
    mutations.forEach(mutation => {
        mutation.addedNodes.forEach(node => {
            if (node.nodeType === Node.ELEMENT_NODE) {
                // 如果是单个资源元素
                monitorResource(node);
                // 如果是包含子元素的容器,递归监控所有子资源
                const imgs = node.querySelectorAll('img');
                const scripts = node.querySelectorAll('script');
                const links = node.querySelectorAll('link[rel="stylesheet"]');
                [...imgs, ...scripts, ...links].forEach(el => monitorResource(el));
            }
        });
    });
});

// 启动DOM监控
observer.observe(document.body, {
    childList: true,
    subtree: true
});

// 监控页面初始加载的资源
window.addEventListener('load', () => {
    // 初始页面的图片、脚本、样式
    const initialImgs = document.querySelectorAll('img');
    const initialScripts = document.querySelectorAll('script');
    const initialLinks = document.querySelectorAll('link[rel="stylesheet"]');
    
    [...initialImgs, ...initialScripts, ...initialLinks].forEach(el => monitorResource(el));
    
    // 初始资源添加后检查一次
    checkAllLoaded();
});

代码说明

  1. 资源状态管理:用pendingResources这个Set来存储所有待加载的资源,每完成一个(成功或失败)就从Set中移除,当Set为空时触发完成回调。
  2. XHR拦截:重写XMLHttpRequest的open和send方法,监听AJAX请求的load事件,提取返回HTML中的资源并加入监控。
  3. DOM监控:用MutationObserver监听页面DOM的变化,捕捉动态添加的元素,自动监控这些元素对应的资源。
  4. 初始资源监控:在window.load事件中,监控页面初始渲染的所有图片、脚本和样式表。

注意事项

  • 你可以根据网站实际加载的资源类型(比如视频、字体),扩展monitorResource函数的逻辑,加入对应资源的监控。
  • 对于跨域资源,要确保网站允许加载(没有CORS限制),否则Image对象的onerror会触发,但不影响整体状态判断。
  • 如果AJAX返回的是JSON数据,里面包含资源URL,你需要修改XHR拦截部分的逻辑,从JSON中提取URL并监控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:05:39