// ==UserScript==
// @name Web Comprehensive Optimization Script(web综合优化脚本)
// @namespace http://tampermonkey.net/
// @version 2.5
// @description Optimize rendering, event handling, resource loading, and more.
// @author KiwiFruit
// @match *://*/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// ========================
// 配置中心
// ========================
const config = {
debug: false, // 开启调试日志
throttleDelay: 200, // 节流延迟
debounceDelay: 300, // 防抖延迟
retryAttempts: 3, // 资源加载最大重试次数
retryDelay: 1000, // 重试间隔
criticalCssPaths: { // 关键CSS路径映射
'example.com': '/styles/example-critical.css',
'anotherwebsite.com': '/styles/anotherwebsite-critical.css',
default: '/styles/default-critical.css'
},
lazyCssSelector: '.lazy-css', // 非首屏CSS占位选择器
rootMarginFactor: 0.1, // IntersectionObserver根边距系数
enableWebWorker: true // 是否启用Web Worker(示例开关)
};
// ========================
// 日志系统(支持分级)
// ========================
const logger = {
debug: (msg) => {
if (config.debug) console.log(`[DEBUG] ${msg}`);
},
warn: (msg) => console.warn(`[WARN] ${msg}`),
error: (msg) => console.error(`[ERROR] ${msg}`)
};
// ========================
// 工具函数
// ========================
const throttle = (func, delay) => {
let lastCall = 0;
return function (...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
func.apply(this, args);
}
};
};
const debounce = (func, delay) => {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), delay);
};
};
const calculateRootMargin = () => {
const windowHeight = window.innerHeight;
const marginBottom = Math.max(0, windowHeight * config.rootMarginFactor);
return `0px 0px ${marginBottom}px 0px`;
};
// ========================
// 资源加载器(带重试)
// ========================
class ResourceLoader {
static loadResource(url, type) {
return new Promise((resolve, reject) => {
const element = document.createElement(type === 'script' ? 'script' : 'link');
if (type === 'script') {
element.src = url;
} else {
element.rel = 'stylesheet';
element.href = url;
}
element.onload = resolve;
element.onerror = () => reject(new Error(`${type} loading failed: ${url}`));
document.head.appendChild(element);
});
}
static async loadWithRetry(loaderFn, maxRetries = config.retryAttempts, delay = config.retryDelay) {
for (let i = 0; i < maxRetries; i++) {
try {
return await loaderFn();
} catch (error) {
if (i === maxRetries - 1) {
logger.error(`Resource load failed after ${maxRetries} attempts: ${error.message}`);
throw error;
}
logger.warn(`Retrying in ${delay / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
static async loadStylesheet(href) {
await this.loadWithRetry(() => this.loadResource(href, 'stylesheet'));
logger.debug(`Stylesheet loaded: ${href}`);
}
static async loadScript(src) {
await this.loadWithRetry(() => this.loadResource(src, 'script'));
logger.debug(`Script loaded: ${src}`);
}
}
// ========================
// 核心性能指标监控
// ========================
class PerformanceMonitor {
static init() {
// FCP(首次内容绘制)
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
logger.debug(`FCP: ${entries[0].startTime}ms`);
}).observe({ type: 'paint', buffered: true });
// LCP(最大内容绘制)
new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
logger.debug(`LCP: ${lastEntry.startTime}ms`);
observer.disconnect();
}).observe({ type: 'largest-contentful-paint', buffered: true });
// CLS(累积布局偏移)
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
let totalCLS = 0;
entries.forEach(entry => {
if (!entry.hadRecentInput) {
totalCLS += entry.value;
}
});
logger.debug(`CLS: ${totalCLS.toFixed(3)}`);
}).observe({ type: 'layout-shift', buffered: true });
}
}
// ========================
// 硬件加速优化
// ========================
class HardwareAcceleration {
static init() {
const className = 'enable-hardware-acceleration';
const styleSheet = `
.${className} {
transform: translateZ(0) !important;
will-change: transform !important;
}
`;
const styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.appendChild(document.createTextNode(styleSheet));
document.head.appendChild(styleElement);
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add(className);
} else {
entry.target.classList.remove(className);
}
});
}, { rootMargin: calculateRootMargin(), threshold: 0 });
return observer;
}
}
// ========================
// 非首屏CSS懒加载(兼容回退)
// ========================
class LazyCssLoader {
static init() {
if (!window.IntersectionObserver) {
this.fallback();
return;
}
const observer = new IntersectionObserver((entries, io) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const element = entry.target;
const href = element.getAttribute('data-lazy-css');
if (href) {
ResourceLoader.loadStylesheet(href).then(() => {
if (element.parentElement) {
element.parentElement.removeChild(element);
}
});
}
io.unobserve(element);
}
});
}, { rootMargin: calculateRootMargin(), threshold: 0 });
document.querySelectorAll(config.lazyCssSelector).forEach(el => observer.observe(el));
}
static fallback() {
logger.warn('IntersectionObserver not supported, falling back to polling...');
const checkVisible = () => {
document.querySelectorAll(config.lazyCssSelector).forEach(element => {
const rect = element.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
const href = element.getAttribute('data-lazy-css');
ResourceLoader.loadStylesheet(href).then(() => {
if (element.parentElement) {
element.parentElement.removeChild(element);
}
});
}
});
};
setInterval(checkVisible, 500);
}
}
// ========================
// Web Worker(示例)
// ========================
class WorkerManager {
static init() {
if (!config.enableWebWorker || !window.Worker) {
logger.warn('Web Worker not available or disabled.');
return;
}
const workerCode = `
self.onmessage = function(e) {
const result = heavyProcessing(e.data);
self.postMessage(result);
};
function heavyProcessing(data) {
let sum = 0;
for (let i = 0; i < data; i++) {
sum += Math.sqrt(i);
}
return sum;
}
`;
const blob = new Blob([workerCode], { type: 'application/javascript' });
const url = URL.createObjectURL(blob);
const worker = new Worker(url);
worker.onmessage = function(e) {
logger.debug('Worker result:', e.data);
};
worker.postMessage(1000000); // 示例任务
}
}
// ========================
// 事件绑定(节流/防抖)
// ========================
class EventManager {
static init() {
window.addEventListener('scroll', throttle(() => {
logger.debug('Scroll event triggered (throttled)');
}, config.throttleDelay));
window.addEventListener('resize', debounce(() => {
logger.debug('Resize event triggered (debounced)');
}, config.debounceDelay));
}
}
// ========================
// DOM变化监听
// ========================
class DomMonitor {
static init() {
const observer = new MutationObserver(throttle(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.matches(config.lazyCssSelector)) {
LazyCssLoader.init();
}
});
});
}, 100));
observer.observe(document.body, { childList: true, subtree: true });
}
}
// ========================
// 初始化流程
// ========================
class App {
static async init() {
// 性能监控
PerformanceMonitor.init();
// 关键CSS预加载
const hostname = window.location.hostname;
let criticalCssUrl;
if (hostname.includes('example.com')) {
criticalCssUrl = config.criticalCssPaths['example.com'];
} else if (hostname.includes('anotherwebsite.com')) {
criticalCssUrl = config.criticalCssPaths['anotherwebsite.com'];
} else {
criticalCssUrl = config.criticalCssPaths.default;
}
if (criticalCssUrl) {
try {
await ResourceLoader.loadStylesheet(`${window.location.origin}${criticalCssUrl}`);
} catch (error) {
logger.error(`Failed to load critical CSS: ${error.message}`);
}
}
// 初始化各模块
HardwareAcceleration.init();
LazyCssLoader.init();
DomMonitor.init();
EventManager.init();
WorkerManager.init();
}
}
// ========================
// 页面生命周期管理
// ========================
document.addEventListener("DOMContentLoaded", () => {
App.init().catch(error => logger.error(`Initialization failed: ${error.message}`));
});
window.addEventListener("beforeunload", () => {
// 清理资源(如MutationObserver)
logger.debug('Page is unloading...');
});
})();