Greasy Fork is available in English.
精密加载耗时分析器(DOMContentLoaded+首次可视时间+内容完全可见时间)
当前为
// ==UserScript==
// @name 测试页面加载速度
// @namespace https://viayoo.com/
// @version 4.2
// @license MIT
// @description 精密加载耗时分析器(DOMContentLoaded+首次可视时间+内容完全可见时间)
// @author ChatGPT & Grok & DeepSeek
// @match *://*/*
// @grant GM_registerMenuCommand
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
let currentDuration = null;
let domContentLoadedTime = null;
let fcp = null, lcp = null;
const getLoadDuration = () => {
const [navEntry] = performance.getEntriesByType('navigation');
return navEntry ? navEntry.duration : null;
};
const getDomContentLoadedTime = () => {
const [navEntry] = performance.getEntriesByType('navigation');
return (navEntry && navEntry.domContentLoadedEventEnd) || null;
};
const truncateDecimals = (num, decimals) => {
const factor = Math.pow(10, decimals);
return Math.floor(num * factor) / factor;
};
const formatTime = (time) => {
if (time >= 10000) {
return `${truncateDecimals(time / 1000, 2).toFixed(2)}s`;
} else {
return `${truncateDecimals(time, 2).toFixed(2)}ms`;
}
};
const showViaToast = (duration) => {
if (window.via && typeof window.via.toast === 'function') {
const message = duration ? `加载耗时: ${formatTime(duration)}` : '加载耗时: 未知';
window.via.toast(message);
return true;
}
return false;
};
const showDomNotification = (duration) => {
const container = document.createElement('div');
const shadow = container.attachShadow({ mode: 'closed' });
const elem = document.createElement('div');
elem.className = 'load-time-final';
elem.textContent = duration ? `加载耗时: ${formatTime(duration)}` : '未知';
elem.style.opacity = '0';
elem.style.transition = 'opacity 0.15s ease-out';
const style = document.createElement('style');
style.textContent = '.load-time-final{position:fixed;bottom:60px;left:50%;transform:translateX(-50%);background:rgba(255,255,255,0.96);backdrop-filter:blur(8px);padding:10px 22px;border-radius:6px;font-family:"JetBrains Mono",monospace;color:#2c3e50;box-shadow:0 4px 20px rgba(0,0,0,0.1);z-index:2147483647;border:1px solid rgba(0,0,0,0.06);font-size:14px;white-space:nowrap;}';
shadow.appendChild(style);
shadow.appendChild(elem);
document.body.appendChild(container);
requestAnimationFrame(() => {
elem.style.opacity = '1';
});
setTimeout(() => {
elem.style.opacity = '0';
setTimeout(() => container.remove(), 150);
}, 1500);
};
const showDuration = (duration) => {
if (!showViaToast(duration)) {
showDomNotification(duration);
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
domContentLoadedTime = performance.now();
});
} else {
domContentLoadedTime = getDomContentLoadedTime();
}
try {
new PerformanceObserver((list) => {
for (const e of list.getEntries()) {
if (e.name === 'first-contentful-paint' && !fcp) fcp = e.startTime;
}
}).observe({ type: 'paint', buffered: true });
new PerformanceObserver((list) => {
const ents = list.getEntries();
if (ents.length) lcp = ents[ents.length - 1].startTime;
}).observe({ type: 'largest-contentful-paint', buffered: true });
} catch (e) {
console.warn('浏览器不支持 FCP/LCP 监控:', e);
}
window.addEventListener('load', () => {
requestAnimationFrame(() => {
currentDuration = getLoadDuration();
showDuration(currentDuration);
});
}, { once: true });
GM_registerMenuCommand('显示性能指标', () => {
if (currentDuration === null) {
currentDuration = getLoadDuration();
}
const domContentLoadedText = domContentLoadedTime ? formatTime(domContentLoadedTime) : '未知';
const fcpText = fcp ? formatTime(fcp) : '未知';
const lcpText = lcp ? formatTime(lcp) : '未知';
const durationText = currentDuration ? formatTime(currentDuration) : '未知';
alert(`DOMContentLoaded: ${domContentLoadedText}\n首次可视时间 (FCP): ${fcpText}\n内容完全可见时间 (LCP): ${lcpText}\n页面完全加载耗时: ${durationText}`);
});
})();