// ==UserScript== // @name Web性能优化工具箱(主版) // @namespace http://tampermonkey.net/ // @version 3.8.2-fusion // @description SPA兼容懒加载+预连接+硬件加速+集成Core Web Vitals实时监控面板 // @author KiwiFruit // @match *://*/* // @exclude *://*.weibo.com/* // @exclude *://*.x.com/* // @exclude *://*.chat.z.ai* // @exclude *://*.doubao.com/* // @grant none // @license MIT // @run-at document-start // @downloadURL none // ==/UserScript== (function() { 'use strict'; // ======================== // 1. 环境检测与工具函数(复用脚本2的Env/Utils) // ======================== const Env = { features: { nativeLazyLoad: 'loading' in HTMLImageElement.prototype, intersectionObserver: 'IntersectionObserver' in window, mutationObserver: 'MutationObserver' in window, performanceObserver: 'PerformanceObserver' in window, requestIdleCallback: 'requestIdleCallback' in window, contentVisibility: CSS.supports('content-visibility', 'hidden'), webgpu: typeof GPU !== 'undefined' && !!navigator.gpu }, performanceTier: (() => { if (navigator.hardwareConcurrency >= 4) return 2; if (window.devicePixelRatio <= 1.5) return 1; return 0; })(), networkType: navigator.connection?.effectiveType || 'unknown' }; const Utils = { ric: (cb, timeout = 2000) => { if (Env.features.requestIdleCallback) { return requestIdleCallback(cb, { timeout }); } return setTimeout(cb, 16); }, cancelRic: (id) => { if (Env.features.requestIdleCallback) { cancelIdleCallback(id); } else { clearTimeout(id); } }, throttle: (fn, limit) => { let inThrottle; return function(...args) { if (!inThrottle) { fn.apply(this, args); inThrottle = true; setTimeout(() => { inThrottle = false; }, limit); } }; } }; // ======================== // 2. 统一配置(整合两个脚本的配置) // ======================== const Config = { debug: false, ui: { enabled: true, zIndex: 9999, autoHideDelay: 3000, triggerDistance: 120, statsUpdateInterval: 3000, width: 320 }, lazyLoad: { enabled: true, selector: 'img[data-src]:not([data-src=""]), img[original-src], img[data-original], img.lazy, iframe[data-src]', preloadDistance: 120, useMutationObserver: true // 启用MutationObserver以支持SPA动态内容 }, hardwareAcceleration: { enabled: true, selector: 'header, nav, aside, .sticky, .fixed' }, contentVisibility: { enabled: true, selector: '[data-perfopt-cv]' }, preconnect: { enabled: true, dynamic: true, maxDomains: 6 }, blacklistedDomains: ['weibo.com', 'weibo.cn', 'x.com', 'chat.z.ai', 'doubao.com', 'kimi.com', 'qianwen.com'] }; const Logger = { info: (m, msg) => console.log(`[PerfOpt][${m}]`, msg), warn: (m, msg) => console.warn(`[PerfOpt][${m}]`, msg), error: (m, msg) => console.error(`[PerfOpt][${m}]`, msg) }; // ======================== // 3. 基础模块类(复用脚本2的BaseModule) // ======================== class BaseModule { constructor(name) { this.moduleName = name; this.initialized = false; this._handlers = []; this._timers = []; this._observers = []; } init() { if (this.initialized) { Logger.warn(this.moduleName, '重复初始化'); return; } this.initialized = true; } on(target, type, fn, options) { if (!target || typeof target.addEventListener !== 'function') { return; } target.addEventListener(type, fn, options); this._handlers.push({ target, type, fn }); } off(target, type, fn) { if (!target || typeof target.removeEventListener !== 'function') { return; } target.removeEventListener(type, fn); } setTimer(fn, delay) { const id = setTimeout(fn, delay); this._timers.push(id); return id; } clearTimer(id) { const idx = this._timers.indexOf(id); if (idx > -1) { clearTimeout(this._timers[idx]); this._timers.splice(idx, 1); } } setInterval(fn, delay) { const id = setInterval(fn, delay); this._timers.push(id); return id; } observeMutations(callback, target, options) { if (!Env.features.mutationObserver || !target) { return null; } const mo = new MutationObserver(Utils.throttle(callback, 100)); mo.observe(target, options || { childList: true, subtree: true }); this._observers.push(mo); return mo; } destroy() { this._handlers.forEach(({ target, type, fn }) => { try { this.off(target, type, fn); } catch (e) {} }); this._handlers = []; this._timers.forEach(id => { try { clearTimeout(id); clearInterval(id); } catch (e) {} }); this._timers = []; this._observers.forEach(obs => { try { obs.disconnect(); } catch (e) {} }); this._observers = []; this.initialized = false; } } // ======================== // ======================== // 4. 统一性能监控模块 // ======================== class UnifiedPerformanceMonitor extends BaseModule { constructor() { super('UnifiedPerformanceMonitor'); this.metrics = { fcp: null, lcp: null, cls: 0, inp: null, ttfb: null, longTasks: [] }; this._obsInstances = []; } init() { if (!Env.features.performanceObserver) { Logger.warn('UnifiedPerformanceMonitor', '浏览器不支持 PerformanceObserver'); return; } super.init(); this._readHistoricalData(); this._setupObservers(); this.on(document, 'visibilitychange', () => { if (document.visibilityState === 'visible') { this._readHistoricalData(); } }); Logger.info('UnifiedPerformanceMonitor', '初始化完成'); } _readHistoricalData() { try { // 修复 1: 使用现代 Navigation Timing API 替代废弃的 performance.timing const navEntry = performance.getEntriesByType('navigation')[0]; if (navEntry) { this.metrics.ttfb = Math.round(navEntry.responseStart); } else if (performance.timing) { // 降级兼容极旧浏览器(如果必须) this.metrics.ttfb = performance.timing.responseStart - performance.timing.navigationStart; } const paints = performance.getEntriesByType('paint'); paints.forEach(e => { if (e.name === 'first-contentful-paint' && !this.metrics.fcp) { this.metrics.fcp = Math.round(e.startTime); } }); const lcps = performance.getEntriesByType('largest-contentful-paint'); if (lcps.length > 0) { const last = lcps[lcps.length - 1]; this.metrics.lcp = Math.round(last.startTime); } let cls = 0; const shifts = performance.getEntriesByType('layout-shift'); shifts.forEach(e => { if (!e.hadRecentInput) { cls += e.value; } }); this.metrics.cls = cls; const longTasks = performance.getEntriesByType('longtask'); this.metrics.longTasks = longTasks.map(t => ({ duration: t.duration, startTime: t.startTime })); } catch (e) { Logger.error('UnifiedPerformanceMonitor', '读取历史数据失败', e); } } _setupObservers() { // 修复 2: 移除 buffered: true 以消除警告 // 原因:脚本已经在 _readHistoricalData() 中读取了历史数据,观察器只需监听新出现的条目即可。 // 这样既消除了警告,又避免了重复处理数据。 try { const fcpObs = new PerformanceObserver((list) => { list.getEntries().forEach(e => { if (e.name === 'first-contentful-paint') { this.metrics.fcp = Math.round(e.startTime); } }); }); // 仅监听新条目,移除 buffered: true fcpObs.observe({ type: 'paint' }); this._obsInstances.push(fcpObs); } catch (e) { Logger.warn('UnifiedPerformanceMonitor', 'FCP观察器失败'); } try { const lcpObs = new PerformanceObserver((list) => { const entries = list.getEntries(); if (entries.length > 0) { const last = entries[entries.length - 1]; this.metrics.lcp = Math.round(last.startTime); } }); lcpObs.observe({ type: 'largest-contentful-paint' }); this._obsInstances.push(lcpObs); } catch (e) { Logger.warn('UnifiedPerformanceMonitor', 'LCP观察器失败'); } try { const clsObs = new PerformanceObserver((list) => { list.getEntries().forEach(e => { if (!e.hadRecentInput) { this.metrics.cls += e.value; } }); }); clsObs.observe({ type: 'layout-shift' }); this._obsInstances.push(clsObs); } catch (e) { Logger.warn('UnifiedPerformanceMonitor', 'CLS观察器失败'); } try { let maxDuration = 0; const inpObs = new PerformanceObserver((list) => { list.getEntries().forEach(entry => { if (entry.duration > maxDuration) { maxDuration = entry.duration; this.metrics.inp = Math.round(entry.duration); } }); }); // INP 需要监听历史交互,但如果浏览器警告,也可移除 buffered // 为了稳定性,这里也移除 buffered,依赖后续交互捕获 inpObs.observe({ type: 'event' }); this._obsInstances.push(inpObs); } catch (e) { Logger.warn('UnifiedPerformanceMonitor', 'INP观察器失败(浏览器不支持)'); } try { const longTaskObs = new PerformanceObserver((list) => { list.getEntries().forEach(entry => { this.metrics.longTasks.push({ duration: entry.duration, startTime: entry.startTime }); }); }); longTaskObs.observe({ type: 'longtask' }); this._obsInstances.push(longTaskObs); } catch (e) { Logger.warn('UnifiedPerformanceMonitor', 'Long Task观察器失败'); } } getMetrics() { try { const lcps = performance.getEntriesByType('largest-contentful-paint'); if (lcps.length > 0) { const last = lcps[lcps.length - 1]; if (last.startTime > (this.metrics.lcp || 0)) { this.metrics.lcp = Math.round(last.startTime); } } } catch (e) {} return { fcp: this.metrics.fcp, lcp: this.metrics.lcp, cls: this.metrics.cls, inp: this.metrics.inp, ttfb: this.metrics.ttfb, longTasks: this.metrics.longTasks }; } destroy() { this._obsInstances.forEach(obs => { try { obs.disconnect(); } catch (e) {} }); this._obsInstances = []; super.destroy(); } } // ======================== // 5. 统一图片懒加载模块 // ======================== class UnifiedImageOptimizer extends BaseModule { constructor() { super('UnifiedImageOptimizer'); this.io = null; this.mo = null; this._observedElements = new WeakSet(); this.isSPA = Env.features.nativeLazyLoad; // 复用脚本1的SPA检测 } init() { if (!Config.lazyLoad.enabled) { Logger.info('UnifiedImageOptimizer', '已禁用'); return; } super.init(); if (document.readyState === 'loading') { this.on(document, 'DOMContentLoaded', () => this._setup()); } else { this._setup(); } } _setup() { if (Env.features.intersectionObserver) { this._setupIntersectionObserver(); } if (Config.lazyLoad.useMutationObserver && Env.features.mutationObserver) { this._setupMutationObserver(); } Logger.info('UnifiedImageOptimizer', '设置完成'); } _setupIntersectionObserver() { this.io = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { this._loadImage(entry.target); this.io.unobserve(entry.target); this._observedElements.delete(entry.target); } }); }, { rootMargin: `${Config.lazyLoad.preloadDistance}px 0px`, threshold: 0.01 }); const elements = document.querySelectorAll(Config.lazyLoad.selector); elements.forEach(el => { if (!this._observedElements.has(el)) { this._observedElements.add(el); this.io.observe(el); } }); } _setupMutationObserver() { this.mo = this.observeMutations((mutations) => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { if (node.matches && node.matches(Config.lazyLoad.selector)) { this._observeElement(node); } if (node.querySelectorAll) { node.querySelectorAll(Config.lazyLoad.selector).forEach(child => { this._observeElement(child); }); } } }); }); }, document.body, { childList: true, subtree: true }); } _observeElement(el) { if (!this.io || this._observedElements.has(el)) { return; } this._observedElements.add(el); this.io.observe(el); } _loadImage(el) { if (!el.dataset.src) { return; } const src = el.dataset.src; delete el.dataset.src; if (el.tagName === 'IFRAME') { el.src = src; } else { el.src = src; } // SPA场景下的额外优化(复用脚本1的逻辑) if (this.isSPA) { el.decoding = 'async'; // 离屏异步解码,减少主线程阻塞 } } destroy() { if (this.io) { this.io.disconnect(); this.io = null; } if (this.mo) { this.mo.disconnect(); this.mo = null; } super.destroy(); } } // ======================== // 6. 预连接优化模块(复用脚本2的PreconnectOptimizer) // ======================== class PreconnectOptimizer extends BaseModule { constructor() { super('PreconnectOptimizer'); this._appliedDomains = new Set(); } init() { if (!Config.preconnect.enabled) { Logger.info('PreconnectOptimizer', '已禁用'); return; } super.init(); Utils.ric(() => { this._analyzeAndApply(); }, 3000); } _analyzeAndApply() { const domains = new Set(); const selectors = [ 'link[rel="stylesheet"][href^="http"]', 'script[src^="http"]', 'img[src^="http"]', 'iframe[src^="http"]', 'source[srcset^="http"]' ]; selectors.forEach(selector => { document.querySelectorAll(selector).forEach(el => { try { const url = new URL(el.href || el.src); if (url.hostname !== window.location.hostname) { domains.add(url.hostname); } } catch (e) {} }); }); const domainList = Array.from(domains).slice(0, Config.preconnect.maxDomains); domainList.forEach(domain => { if (this._appliedDomains.has(domain)) { return; } if (document.querySelector(`link[rel*="preconnect"][href*="${domain}"]`)) { this._appliedDomains.add(domain); return; } const link = document.createElement('link'); link.rel = 'preconnect'; link.href = `https://${domain}`; link.crossOrigin = 'anonymous'; document.head.appendChild(link); this._appliedDomains.add(domain); }); Logger.info('PreconnectOptimizer', `已优化 ${domainList.length} 个域名`); } destroy() { this._appliedDomains.clear(); super.destroy(); } } // ======================== // ======================== // 7. 统一滚动优化模块 (静默优化版) // ======================== class UnifiedScrollOptimizer extends BaseModule { constructor() { super('UnifiedScrollOptimizer'); this._originalAddEventListener = null; } init() { super.init(); // 合并优化逻辑,静默执行 this._optimizePassiveEvents(); this._applyHardwareAcceleration(); } _optimizePassiveEvents() { // 保存原生方法以便恢复 this._originalAddEventListener = EventTarget.prototype.addEventListener; const self = this; const passiveEvents = ['wheel', 'mousewheel', 'touchstart', 'touchmove', 'scroll']; // 单次补丁:同时处理优化,不再重复包裹 EventTarget.prototype.addEventListener = function(type, handler, options) { // 核心优化:强制被动监听器,提升滚动流畅度 if (passiveEvents.includes(type) && !options?.passive) { if (this === window || this === document || this === document.body) { options = typeof options === 'object' ? { ...options, passive: true } : { passive: true, capture: options === true }; } } // 直接调用原生(或上一层)方法,无额外日志 return self._originalAddEventListener.call(this, type, handler, options); }; } _applyHardwareAcceleration() { if (!Config.hardwareAcceleration.enabled || !Env.features.webgpu) { return; } const elements = document.querySelectorAll(Config.hardwareAcceleration.selector); elements.forEach(el => { el.style.willChange = 'transform'; el.style.transform = 'translateZ(0)'; }); } destroy() { // 重要:恢复原生 addEventListener,防止内存泄漏或冲突 if (this._originalAddEventListener) { EventTarget.prototype.addEventListener = this._originalAddEventListener; this._originalAddEventListener = null; } super.destroy(); } } // ======================== // 8. 统一空闲任务调度 // ======================== class UnifiedIdleScheduler extends BaseModule { constructor() { super('UnifiedIdleScheduler'); this.tasks = []; } init() { super.init(); window.addEventListener('load', () => { setTimeout(() => this.schedule(), 1000); }); } add(task, priority = 'normal') { this.tasks.push({ fn: task, priority }); this.tasks.sort((a, b) => { const p = { high: 0, normal: 1, low: 2 }; return p[a.priority] - p[b.priority]; }); } schedule() { if (this.tasks.length === 0) return; Utils.ric((deadline) => { while (deadline.timeRemaining() > 30 && this.tasks.length > 0) { const task = this.tasks.shift(); try { task.fn(); } catch (e) { Logger.error('UnifiedIdleScheduler', '空闲任务失败:', e); } } if (this.tasks.length > 0) { this.schedule(); } }, { timeout: 5000 }); } destroy() { super.destroy(); } } // ======================== // 9. UI控制器(复用脚本2的UIController,展示融合后的监控数据) // ======================== class UIController extends BaseModule { constructor() { super('UIController'); this.panelVisible = false; this.button = null; this.panel = null; this.monitor = null; this.statsTimer = null; this.isInTriggerZone = false; this._hideTimer = null; this._throttledMouseMove = null; } setPerformanceMonitor(monitor) { this.monitor = monitor; } init() { if (!Config.ui.enabled) { Logger.info('UIController', '已禁用'); return; } super.init(); if (document.readyState === 'loading') { this.on(document, 'DOMContentLoaded', () => this._createUI()); } else { this._createUI(); } } _createUI() { if (!document.body) { Logger.warn('UIController', 'body未就绪,延迟创建'); setTimeout(() => this._createUI(), 100); return; } const width = Config.ui.width; const style = document.createElement('style'); style.textContent = ` .perfopt-btn { position: fixed !important; bottom: 20px !important; right: 20px !important; width: 48px !important; height: 48px !important; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; border-radius: 50% !important; box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; z-index: ${Config.ui.zIndex} !important; transition: transform 0.3s ease, opacity 0.3s ease, right 0.3s ease !important; font-size: 20px !important; opacity: 1 !important; pointer-events: auto !important; user-select: none !important; } .perfopt-btn:hover { transform: scale(1.1) !important; } .perfopt-btn.hidden { right: -40px !important; opacity: 0.3 !important; pointer-events: none !important; } .perfopt-panel { position: fixed !important; bottom: 80px !important; right: 20px !important; width: ${width}px !important; max-height: 85vh !important; background: rgba(255,255,255,0.98) !important; backdrop-filter: blur(10px) !important; border-radius: 12px !important; box-shadow: 0 8px 32px rgba(0,0,0,0.15) !important; padding: 20px !important; z-index: ${Config.ui.zIndex - 1} !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; font-size: 13px !important; display: none !important; opacity: 0 !important; transform: translateY(10px) !important; transition: opacity 0.3s ease, transform 0.3s ease !important; overflow-y: auto !important; box-sizing: border-box !important; } .perfopt-panel.visible { display: block !important; opacity: 1 !important; transform: translateY(0) !important; } .perfopt-header { font-weight: 600 !important; margin-bottom: 16px !important; padding-bottom: 10px !important; border-bottom: 1px solid rgba(0,0,0,0.1) !important; font-size: 15px !important; color: #333 !important; display: flex !important; align-items: center !important; gap: 6px !important; } .perfopt-row { display: flex !important; justify-content: space-between !important; align-items: center !important; margin: 10px 0 !important; line-height: 1.5 !important; } .perfopt-label { color: #666 !important; font-size: 13px !important; } .perfopt-value { font-family: "SF Mono", Monaco, monospace !important; font-weight: 600 !important; font-size: 13px !important; font-variant-numeric: tabular-nums !important; } .perfopt-good { color: #22c55e !important; } .perfopt-warn { color: #f59e0b !important; } .perfopt-bad { color: #ef4444 !important; } .perfopt-footer { margin-top: 16px !important; padding-top: 12px !important; border-top: 1px solid rgba(0,0,0,0.1) !important; font-size: 11px !important; color: #999 !important; line-height: 1.5 !important; } `; document.head.appendChild(style); this.button = document.createElement('div'); this.button.className = 'perfopt-btn'; this.button.innerHTML = '⚡'; this.button.title = '性能监控 (靠近显示)'; document.body.appendChild(this.button); this.panel = document.createElement('div'); this.panel.className = 'perfopt-panel'; this.panel.innerHTML = `
Core Web Vitals
FCP (首次绘制) --
LCP (最大内容) --
CLS (布局偏移) --
INP (交互延迟) --
TTFB (首字节) --
Long Tasks (卡顿) --
`; document.body.appendChild(this.panel); this._setupEvents(); this._startHideTimer(); Logger.info('UIController', 'UI创建成功'); } _setupEvents() { if (!this.button || !this.panel) { return; } this._throttledMouseMove = Utils.throttle((e) => { if (this.panelVisible) { return; } const rect = this.button.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; const distance = Math.sqrt( Math.pow(e.clientX - centerX, 2) + Math.pow(e.clientY - centerY, 2) ); if (distance <= Config.ui.triggerDistance && !this.isInTriggerZone) { this.isInTriggerZone = true; this._showButton(); this._clearHideTimer(); } else if (distance > Config.ui.triggerDistance && this.isInTriggerZone) { this.isInTriggerZone = false; this._startHideTimer(); } }, 50); this.on(document, 'mousemove', this._throttledMouseMove); this.on(document, 'click', (e) => { if (this.panelVisible && !this.button.contains(e.target) && !this.panel.contains(e.target)) { this._closePanel(); } }); this.on(this.button, 'click', (e) => { e.stopPropagation(); if (this.panelVisible) { this._closePanel(); } else { this._openPanel(); } }); this.on(this.button, 'mouseenter', () => { this._clearHideTimer(); }); this.on(this.button, 'mouseleave', () => { if (!this.panelVisible) { this._startHideTimer(); } }); } _showButton() { if (this.button) { this.button.classList.remove('hidden'); } } _hideButton() { if (this.button && !this.panelVisible) { this.button.classList.add('hidden'); } } _openPanel() { this.panelVisible = true; this.panel.classList.add('visible'); this._showButton(); this._updateStats(); if (this.statsTimer) { clearInterval(this.statsTimer); } this.statsTimer = this.setInterval(() => { this._updateStats(); }, Config.ui.statsUpdateInterval); } _closePanel() { this.panelVisible = false; this.panel.classList.remove('visible'); this._startHideTimer(); if (this.statsTimer) { clearInterval(this.statsTimer); this.statsTimer = null; } } _startHideTimer() { this._clearHideTimer(); this._hideTimer = this.setTimer(() => { this._hideButton(); }, Config.ui.autoHideDelay); } _clearHideTimer() { if (this._hideTimer) { this.clearTimer(this._hideTimer); this._hideTimer = null; } } _updateStats() { if (!this.monitor) { return; } const m = this.monitor.getMetrics(); const setVal = (id, val, good, bad, unit = '') => { const el = document.getElementById(id); if (!el) { return; } if (val === null || val === undefined) { el.textContent = '--'; el.className = 'perfopt-value'; return; } const num = typeof val === 'number' ? val : parseFloat(val); el.textContent = unit ? `${Math.round(num)}${unit}` : num.toFixed(3); let clsName = 'perfopt-value '; if (num < good) { clsName += 'perfopt-good'; } else if (num < bad) { clsName += 'perfopt-warn'; } else { clsName += 'perfopt-bad'; } el.className = clsName; }; setVal('po-fcp', m.fcp, 1800, 3000, 'ms'); setVal('po-lcp', m.lcp, 2500, 4000, 'ms'); setVal('po-cls', m.cls, 0.1, 0.25); setVal('po-inp', m.inp, 200, 500, 'ms'); setVal('po-ttfb', m.ttfb, 600, 1000, 'ms'); // 展示Long Tasks数量 const longTasks = m.longTasks.filter(t => t.duration > 200); setVal('po-longtasks', longTasks.length, 0, 3, '次'); } destroy() { if (this.statsTimer) { clearInterval(this.statsTimer); this.statsTimer = null; } this._throttledMouseMove = null; super.destroy(); } } // ======================== // 10. 主应用控制器(整合所有模块) // ======================== class UnifiedAppController { constructor() { this.modules = {}; } init() { const hostname = window.location.hostname; const isBlacklisted = Config.blacklistedDomains.some(d => hostname.includes(d)); if (isBlacklisted) { Logger.info('UnifiedAppController', '域名在黑名单中,停止加载'); return; } Logger.info('UnifiedAppController', '开始初始化'); this.modules.monitor = new UnifiedPerformanceMonitor(); this.modules.monitor.init(); this.modules.preconnect = new PreconnectOptimizer(); this.modules.preconnect.init(); this.modules.idleScheduler = new UnifiedIdleScheduler(); this.modules.idleScheduler.init(); this.modules.scrollOptimizer = new UnifiedScrollOptimizer(); this.modules.scrollOptimizer.init(); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { Utils.ric(() => this._initDOMModules(), 100); }); } else { Utils.ric(() => this._initDOMModules(), 100); } window.addEventListener('beforeunload', () => { this.destroy(); }); } _initDOMModules() { Logger.info('UnifiedAppController', '初始化DOM模块'); this.modules.images = new UnifiedImageOptimizer(); this.modules.images.init(); this.modules.ui = new UIController(); this.modules.ui.setPerformanceMonitor(this.modules.monitor); this.modules.ui.init(); } destroy() { Object.values(this.modules).forEach(m => { if (m && typeof m.destroy === 'function') { m.destroy(); } }); this.modules = {}; } } // ======================== // 11. 启动脚本 // ======================== try { const app = new UnifiedAppController(); app.init(); window.UnifiedPerfOptimizer = app; Logger.info('Bootstrap', '脚本加载成功 v3.8.1'); } catch (error) { Logger.error('Bootstrap', `致命错误: ${error.message}`); console.error(error); } })();