如何判断AJAX网站的所有资源(HTML、CSS等)已完全加载?
纯JavaScript实现AJAX驱动网站的全资源加载完成检测
我明白你的痛点——依赖AJAX动态加载资源的网站,普通的window.onload根本没法准确判断所有资源是否加载完成,而且还不能用jQuery。下面给你一套纯JavaScript的解决方案,覆盖你提到的两个疑问,帮你搞定这个问题:
核心思路
要实现这个需求,我们需要做两件关键的事:
- 拦截所有XMLHttpRequest请求:捕获AJAX返回的内容,从中提取出需要加载的资源(比如图片、脚本、样式表)。
- 监控所有资源的加载状态:包括页面初始渲染的资源,以及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(); });
代码说明
- 资源状态管理:用
pendingResources这个Set来存储所有待加载的资源,每完成一个(成功或失败)就从Set中移除,当Set为空时触发完成回调。 - XHR拦截:重写
XMLHttpRequest的open和send方法,监听AJAX请求的load事件,提取返回HTML中的资源并加入监控。 - DOM监控:用
MutationObserver监听页面DOM的变化,捕捉动态添加的元素,自动监控这些元素对应的资源。 - 初始资源监控:在
window.load事件中,监控页面初始渲染的所有图片、脚本和样式表。
注意事项
- 你可以根据网站实际加载的资源类型(比如视频、字体),扩展
monitorResource函数的逻辑,加入对应资源的监控。 - 对于跨域资源,要确保网站允许加载(没有CORS限制),否则
Image对象的onerror会触发,但不影响整体状态判断。 - 如果AJAX返回的是JSON数据,里面包含资源URL,你需要修改XHR拦截部分的逻辑,从JSON中提取URL并监控。
内容的提问来源于stack exchange,提问作者ch1maera
相关产品推荐
相关产品推荐

