如何用JavaScript实时监测网页加载字节数?解决大资源更新停顿问题
实时监测网页加载字节数的解决方案
你当前用PerformanceObserver的方式只能在资源完全加载完成后触发更新,对于大体积资源(如WebGL模型),加载过程中会出现长时间的进度停顿——这是因为Resource Timing API仅提供资源加载完成后的统计数据,无法获取中间加载状态。
下面提供两种可行的实时监控方案:
方案1:手动管控自主发起的资源请求
如果是你通过代码主动加载的资源(比如WebGL 3D模型、自定义脚本),可以直接用XMLHttpRequest的progress事件监听实时加载进度,累加已加载字节数:
let totalBytes = 12295985; // 预设总字节数 let loadedBytes = 0; // 封装带进度监听的资源加载函数 function loadResource(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'blob'; // 根据资源类型调整(如text、arraybuffer) // 记录上一次进度的已加载字节,避免重复累加 let prevLoaded = 0; xhr.addEventListener('progress', (e) => { if (e.lengthComputable) { loadedBytes += e.loaded - prevLoaded; prevLoaded = e.loaded; updateProgress(); } }); xhr.addEventListener('load', () => resolve(xhr.response)); xhr.addEventListener('error', reject); xhr.send(); }); } // 更新进度(可替换为DOM操作更新页面进度条) function updateProgress() { const progressRate = (loadedBytes / totalBytes) * 100; console.log(`已加载:${loadedBytes}字节 | 进度:${progressRate.toFixed(2)}%`); } // 调用示例:加载WebGL模型 loadResource('/path/to/your-large-model.glb');
方案2:拦截页面自动加载的资源
如果是页面中通过<img>、<script>等标签自动加载的资源,可以用MutationObserver监听DOM元素新增,替换为手动XHR加载并监听进度:
let totalBytes = 12295985; let loadedBytes = 0; const loadedResources = new Set(); // 去重,避免重复统计缓存资源 // 监听DOM新增元素 const domObserver = new MutationObserver((mutations) => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.tagName === 'IMG' && node.src) handleImage(node); if (node.tagName === 'SCRIPT' && node.src) handleScript(node); // 可扩展处理<link>、<audio>等其他资源类型 }); }); }); domObserver.observe(document.documentElement, { childList: true, subtree: true }); // 处理图片资源 function handleImage(img) { const src = img.src; if (loadedResources.has(src)) return; loadedResources.add(src); const xhr = new XMLHttpRequest(); xhr.open('GET', src); xhr.responseType = 'blob'; let prevLoaded = 0; xhr.addEventListener('progress', e => { if (e.lengthComputable) { loadedBytes += e.loaded - prevLoaded; prevLoaded = e.loaded; updateProgress(); } }); xhr.addEventListener('load', () => { const blobUrl = URL.createObjectURL(xhr.response); img.src = blobUrl; img.onload = () => URL.revokeObjectURL(blobUrl); // 释放Blob URL }); img.removeAttribute('src'); // 阻止浏览器自动加载 xhr.send(); } // 处理脚本资源 function handleScript(script) { const src = script.src; if (loadedResources.has(src)) return; loadedResources.add(src); const xhr = new XMLHttpRequest(); xhr.open('GET', src); xhr.responseType = 'text'; let prevLoaded = 0; xhr.addEventListener('progress', e => { if (e.lengthComputable) { loadedBytes += e.loaded - prevLoaded; prevLoaded = e.loaded; updateProgress(); } }); xhr.addEventListener('load', () => { const newScript = document.createElement('script'); newScript.textContent = xhr.response; script.parentNode.replaceChild(newScript, script); }); script.removeAttribute('src'); xhr.send(); } function updateProgress() { const progressRate = (loadedBytes / totalBytes) * 100; console.log(`已加载:${loadedBytes}字节 | 进度:${progressRate.toFixed(2)}%`); }
关键注意点
- 跨域资源需要服务器配置
Access-Control-Allow-Origin,否则XHR无法获取资源进度。 - 总字节数如果需要自动计算,可通过HEAD请求批量获取所有资源的
Content-Length并累加,但同样受跨域限制。 - 用
Set或Map记录已加载资源,避免缓存资源被重复统计。
内容的提问来源于stack exchange,提问作者Panoman
相关产品推荐
相关产品推荐

