// 监听页面所有资源加载完成
window.addEventListener('load', function() {
const resources = performance.getEntriesByType('resource');
const totalResources = resources.length;
resources.forEach(resource => {
console.log(`资源: ${resource.name}`);
console.log(`加载耗时: ${resource.duration}ms`);
console.log(`类型: ${resource.initiatorType}`);
});
});
// 实时监控资源加载
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
console.log(`${entry.name} 加载耗时: ${entry.duration}ms`);
});
});
observer.observe({ entryTypes: ['resource'] });
class ResourceProgressTracker {
constructor() {
this.resources = new Map();
this.totalResources = 0;
this.loadedResources = 0;
this.totalSize = 0;
this.loadedSize = 0;
this.callbacks = {
onProgress: null,
onComplete: null
};
}
start() {
// 监听资源加载
const originalFetch = window.fetch;
window.fetch = function(...args) {
const startTime = Date.now();
const url = typeof args[0] === 'string' ? args[0] : args[0].url;
return originalFetch.apply(this, args).then(response => {
const clone = response.clone();
clone.blob().then(blob => {
this._trackResource({
url,
size: blob.size,
type: 'fetch',
duration: Date.now() - startTime
});
});
return response;
});
}.bind(this);
// 监控图片
const originalImage = Image;
window.Image = function() {
const img = new originalImage();
const _src = img.src;
Object.defineProperty(img, 'src', {
set(value) {
const startTime = Date.now();
_src.call(img, value);
img.onload = () => {
this._trackResource({
url: value,
type: 'image',
duration: Date.now() - startTime
});
}.bind(this);
img.onerror = () => {
this._trackResource({
url: value,
type: 'image',
error: true,
duration: Date.now() - startTime
});
}.bind(this);
}
});
return img;
}.bind(this);
}
_trackResource(info) {
const resourceId = Date.now() + Math.random();
this.resources.set(resourceId, info);
this.totalResources++;
if (info.size) {
this.totalSize += info.size;
this.loadedSize += info.size;
}
this.loadedResources++;
this._updateProgress();
}
_updateProgress() {
if (this.callbacks.onProgress) {
const progress = {
loaded: this.loadedResources,
total: this.totalResources,
percentage: (this.loadedResources / this.totalResources * 100).toFixed(2),
loadedSize: this.loadedSize,
totalSize: this.totalSize
};
this.callbacks.onProgress(progress);
}
}
onProgress(callback) {
this.callbacks.onProgress = callback;
}
onComplete(callback) {
this.callbacks.onComplete = callback;
}
}
// 使用示例
const tracker = new ResourceProgressTracker();
tracker.onProgress((progress) => {
console.log(`加载进度: ${progress.percentage}%`);
console.log(`已加载: ${progress.loaded}/${progress.total}`);
});
tracker.start();
function monitorAllResources() {
let total = 0;
let loaded = 0;
const resources = new Set();
// 监听DOM变化,发现新资源
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
findResources(node);
}
});
}
});
});
// 查找元素中的资源
function findResources(element) {
const resourceAttrs = {
img: 'src',
script: 'src',
link: 'href',
iframe: 'src',
audio: 'src',
video: 'src',
source: 'src',
embed: 'src',
object: 'data'
};
// 检查当前元素
const tagName = element.tagName.toLowerCase();
if (resourceAttrs[tagName]) {
const src = element.getAttribute(resourceAttrs[tagName]);
if (src) {
addResource(src, tagName, element);
}
}
// 检查背景图片
const bg = window.getComputedStyle(element).backgroundImage;
if (bg && bg !== 'none') {
const url = bg.match(/url\(['"]?(.*?)['"]?\)/);
if (url && url[1]) {
addResource(url[1], 'background', element);
}
}
// 递归检查子元素
element.querySelectorAll('*').forEach(child => {
findResources(child);
});
}
function addResource(url, type, element) {
if (!resources.has(url)) {
resources.add(url);
total++;
const resource = document.createElement('img');
resource.onload = () => {
loaded++;
updateProgress();
};
resource.onerror = () => {
loaded++;
updateProgress();
};
resource.src = url;
}
}
function updateProgress() {
const progress = {
loaded,
total,
percentage: (loaded / total * 100).toFixed(2)
};
console.log('资源加载进度:', progress);
// 派发自定义事件
window.dispatchEvent(new CustomEvent('resourceProgress', {
detail: progress
}));
if (loaded === total) {
console.log('所有资源加载完成');
window.dispatchEvent(new Event('allResourcesLoaded'));
}
}
// 开始监听
observer.observe(document.body, {
childList: true,
subtree: true
});
// 初始扫描
findResources(document.body);
return {
getProgress: () => ({
loaded,
total,
percentage: total > 0 ? (loaded / total * 100).toFixed(2) : 0
})
};
}
class ComprehensiveResourceMonitor {
constructor() {
this.progress = {
resources: 0,
loaded: 0,
size: { total: 0, loaded: 0 }
};
this.init();
}
init() {
// 1. 使用Performance API获取已有资源
this._initPerformanceAPI();
// 2. 监听动态添加的资源
this._initMutationObserver();
// 3. 劫持资源加载方法
this._interceptResourceLoading();
}
_initPerformanceAPI() {
if (performance && performance.getEntriesByType) {
const resources = performance.getEntriesByType('resource');
this.progress.resources = resources.length;
this.progress.loaded = resources.filter(r => r.duration > 0).length;
}
}
_initMutationObserver() {
this.observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
this._scanForResources(node);
});
});
});
this.observer.observe(document.documentElement, {
childList: true,
subtree: true
});
}
_interceptResourceLoading() {
// 劫持fetch
const originalFetch = window.fetch;
window.fetch = (...args) => {
const start = performance.now();
return originalFetch(...args).then(response => {
this._trackResource('fetch', args[0], performance.now() - start);
return response;
});
};
// 劫持Image
const OriginalImage = window.Image;
window.Image = class extends OriginalImage {
constructor() {
super();
const start = performance.now();
let srcValue = '';
Object.defineProperty(this, 'src', {
get() { return srcValue; },
set(value) {
srcValue = value;
super.src = value;
this.onload = () => {
this._trackResource('image', value, performance.now() - start);
};
}
});
}
};
}
}
// React示例
import React, { useState, useEffect } from 'react';
const ResourceProgress = () => {
const [progress, setProgress] = useState({ loaded: 0, total: 0, percentage: 0 });
useEffect(() => {
const tracker = new ResourceProgressTracker();
tracker.onProgress(setProgress);
tracker.start();
return () => {
// 清理
};
}, []);
return (
<div className="resource-progress">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${progress.percentage}%` }}
/>
</div>
<div className="progress-text">
资源加载: {progress.loaded}/{progress.total} ({progress.percentage}%)
</div>
</div>
);
};
这些方法可以根据实际需求组合使用,提供全面的资源加载监控能力。