// ==UserScript==
// @name web综合优化脚本
// @namespace http://tampermonkey.net/
// @version 3.0.1
// @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: {
'example.com': '/styles/example-critical.css',
'anotherwebsite.com': '/styles/anotherwebsite-critical.css',
default: '/styles/default-critical.css'
},
lazyCssSelector: '.lazy-css',
rootMarginFactor: 0.1,
enableWebWorker: true,
batchStyleUpdate: true
};
// ========================
// 日志系统
// ========================
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 StyleBatchUpdater {
static pendingUpdates = new Map();
static updateScheduled = false;
static batchUpdate(element, styles) {
if (!config.batchStyleUpdate) {
Object.assign(element.style, styles);
return;
}
if (!this.pendingUpdates.has(element)) {
this.pendingUpdates.set(element, {});
}
const currentUpdates = this.pendingUpdates.get(element);
Object.assign(currentUpdates, styles);
if (!this.updateScheduled) {
this.updateScheduled = true;
requestAnimationFrame(() => this.processBatch());
}
}
static processBatch() {
this.pendingUpdates.forEach((styles, element) => {
Object.assign(element.style, styles);
});
this.pendingUpdates.clear();
this.updateScheduled = false;
}
static batchAddClass(elements, className) {
if (!Array.isArray(elements)) elements = [elements];
if (!config.batchStyleUpdate) {
elements.forEach(el => el.classList.add(className));
return;
}
elements.forEach(element => {
if (!this.pendingUpdates.has(element)) {
this.pendingUpdates.set(element, {});
}
const classList = this.pendingUpdates.get(element).classList || [];
classList.push({ action: 'add', className });
this.pendingUpdates.get(element).classList = classList;
});
if (!this.updateScheduled) {
this.updateScheduled = true;
requestAnimationFrame(() => this.processClassBatch());
}
}
static batchRemoveClass(elements, className) {
if (!Array.isArray(elements)) elements = [elements];
if (!config.batchStyleUpdate) {
elements.forEach(el => el.classList.remove(className));
return;
}
elements.forEach(element => {
if (!this.pendingUpdates.has(element)) {
this.pendingUpdates.set(element, {});
}
const classList = this.pendingUpdates.get(element).classList || [];
classList.push({ action: 'remove', className });
this.pendingUpdates.get(element).classList = classList;
});
if (!this.updateScheduled) {
this.updateScheduled = true;
requestAnimationFrame(() => this.processClassBatch());
}
}
static processClassBatch() {
this.pendingUpdates.forEach((operations, element) => {
if (operations.classList) {
operations.classList.forEach(op => {
if (op.action === 'add') {
element.classList.add(op.className);
} else {
element.classList.remove(op.className);
}
});
}
});
this.pendingUpdates.clear();
this.updateScheduled = false;
}
}
// ========================
// 资源加载器
// ========================
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 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) {
StyleBatchUpdater.batchAddClass(entry.target, className);
} else {
StyleBatchUpdater.batchRemoveClass(entry.target, 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)');
this.handleScroll();
}, config.throttleDelay));
window.addEventListener('resize', debounce(() => {
logger.debug('Resize event triggered (debounced)');
this.handleResize();
}, config.debounceDelay));
}
static handleScroll() {
const elements = document.querySelectorAll('.scroll-affect');
const scrollY = window.scrollY;
StyleBatchUpdater.batchUpdate(document.documentElement, {
'--scroll-position': `${scrollY}px`
});
elements.forEach(element => {
const shouldUpdate = element.getBoundingClientRect().top < window.innerHeight * 0.8;
if (shouldUpdate) {
StyleBatchUpdater.batchAddClass(element, 'scrolled');
} else {
StyleBatchUpdater.batchRemoveClass(element, 'scrolled');
}
});
}
static handleResize() {
const width = window.innerWidth;
const breakpoint = 768;
const elements = document.querySelectorAll('.responsive-element');
if (width < breakpoint) {
StyleBatchUpdater.batchAddClass(elements, 'mobile-view');
StyleBatchUpdater.batchRemoveClass(elements, 'desktop-view');
} else {
StyleBatchUpdater.batchAddClass(elements, 'desktop-view');
StyleBatchUpdater.batchRemoveClass(elements, 'mobile-view');
}
}
}
// ========================
// 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() {
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();
logger.debug('Optimization script initialized');
}
}
// ========================
// 页面生命周期管理
// ========================
document.addEventListener("DOMContentLoaded", () => {
App.init().catch(error => logger.error(`Initialization failed: ${error.message}`));
});
window.addEventListener("beforeunload", () => {
StyleBatchUpdater.pendingUpdates.clear();
logger.debug('Page is unloading...');
});
})();