Performance API无法实时反馈图片下载transferSize,如何实现实时监控?
问题描述
我正在使用Performance API监控图片的下载进度,用于实时JPG图像流场景并检测下载是否停滞,希望监控已下载大小是否持续增长。但resource事件仅在下载完成时触发,我的使用代码如下:
var currentObserver = null; function setupObserver(observeUrl) { currentObserver = null; currentObserver = new PerformanceObserver((list, obj) => { list.getEntries().forEach((entry) => { if(entry.name.indexOf(observeUrl) > 0) { console.log("entry transferSize:", observeUrl, entry.transferSize); } }); }); currentObserver.observe({ entryTypes: ["resource"] }); }
请问是否有办法在图片下载过程中获取更多更新,或者是否需要监听其他entryType?感谢您提供任何思路!
解决方案
Performance API 的
resource类型条目确实仅在资源完全下载完成后才会生成,无法用于获取下载过程中的实时进度更新;其他内置的 entryType(比如navigation、mark等)也没有提供实时下载进度的能力。要监控图片下载的实时进度并检测停滞,更可靠的方案是直接使用XMLHttpRequest (XHR) 或 Fetch API 的流式处理能力:
使用XMLHttpRequest监听进度
XHR提供了onprogress事件,可以实时获取已加载字节数和总字节数,同时可以通过定时器检测进度是否停滞:function monitorImageDownload(url) { let lastLoaded = 0; let stagnationTimer = null; const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'blob'; // 若需后续展示图片,可设为blob // 实时进度回调 xhr.onprogress = function(e) { if (e.lengthComputable) { const loaded = e.loaded; const total = e.total; console.log(`已下载: ${loaded}/${total} (${(loaded/total*100).toFixed(2)}%)`); // 检测是否停滞 if (loaded === lastLoaded) { if (!stagnationTimer) { // 超过3秒没变化判定为停滞 stagnationTimer = setTimeout(() => { console.error('下载已停滞'); }, 3000); } } else { lastLoaded = loaded; if (stagnationTimer) { clearTimeout(stagnationTimer); stagnationTimer = null; } } } }; xhr.onload = function() { if (stagnationTimer) clearTimeout(stagnationTimer); console.log('下载完成'); // 若需展示图片,将blob转为objectURL赋值给img // const img = document.createElement('img'); // img.src = URL.createObjectURL(xhr.response); // document.body.appendChild(img); }; xhr.onerror = function() { console.error('下载失败'); }; xhr.send(); return xhr; }使用Fetch API结合ReadableStream(适合流式场景)
对于实时JPG流场景,Fetch的ReadableStream可以逐段读取下载的数据,同时统计已加载字节数:async function monitorStreamDownload(url) { let totalLoaded = 0; let lastLoaded = 0; let stagnationTimer = null; const response = await fetch(url); if (!response.ok) throw new Error(`请求失败: ${response.status}`); const reader = response.body.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; totalLoaded += value.length; console.log(`已下载字节数: ${totalLoaded}`); // 检测停滞 if (totalLoaded === lastLoaded) { if (!stagnationTimer) { stagnationTimer = setTimeout(() => { console.error('流式下载已停滞'); }, 3000); } } else { lastLoaded = totalLoaded; if (stagnationTimer) { clearTimeout(stagnationTimer); stagnationTimer = null; } } // 可在此对流数据做处理,比如实时解析JPG片段(如果是分段流) // processChunk(value); } if (stagnationTimer) clearTimeout(stagnationTimer); console.log('流式下载完成'); }
如果原本是用
<img>标签直接加载图片,需要改为先通过XHR/Fetch下载,再将获取到的Blob转为objectURL赋值给<img>的src属性,这样既能监控进度,又不影响图片展示。
内容的提问来源于stack exchange,提问作者Tom Deblauwe
相关产品推荐
相关产品推荐

