Greasy Fork

Greasy Fork is available in English.

现代Web性能优化工具箱

一个更安全、更灵活的性能优化脚本,包含懒加载、事件节流等实用功能。

当前为 2025-07-30 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         现代Web性能优化工具箱
// @namespace    http://tampermonkey.net/
// @version      3.1.2
// @description  一个更安全、更灵活的性能优化脚本,包含懒加载、事件节流等实用功能。
// @author       KiwiFruit
// @match        *://*/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // ========================
    // 配置中心 - 简化并明确作用域
    // ========================
    const config = {
        debug: false,
        // 事件节流/防抖延迟
        throttleDelay: 200,
        debounceDelay: 300,
        // 重试配置
        retryAttempts: 3,
        retryDelay: 1000,
        // 懒加载配置
        lazyLoad: {
            enabled: true,
            // 用于标记懒加载元素的通用类名
            selector: '.js-lazy-load',
            // 根边距,提前触发加载
            rootMargin: '100px 0px'
        },
        // 硬件加速配置
        hardwareAcceleration: {
            enabled: true,
            // 需要硬件加速的元素选择器
            selector: '.js-animate, .js-transform'
        },
        // Web Worker 配置
        webWorker: {
            enabled: true,
            // 自定义计算函数的占位符
            customTask: null // 可由用户在外部定义
        }
    };

    // ========================
    // 日志系统 - 保持简洁
    // ========================
    const logger = {
        debug: (msg) => { if (config.debug) console.log(`[Optimize] DEBUG: ${msg}`); },
        info: (msg) => console.info(`[Optimize] INFO: ${msg}`),
        warn: (msg) => console.warn(`[Optimize] WARN: ${msg}`),
        error: (msg) => console.error(`[Optimize] ERROR: ${msg}`)
    };

    // ========================
    // 工具函数 - 通用且无副作用
    // ========================
    const utils = {
        /**
         * 节流函数
         * @param {Function} func - 要节流的函数
         * @param {number} delay - 延迟时间(毫秒)
         * @returns {Function} 节流后的函数
         */
        throttle: (func, delay) => {
            let lastCall = 0;
            return function (...args) {
                const now = Date.now();
                if (now - lastCall >= delay) {
                    lastCall = now;
                    func.apply(this, args);
                }
            };
        },

        /**
         * 防抖函数
         * @param {Function} func - 要防抖的函数
         * @param {number} delay - 延迟时间(毫秒)
         * @returns {Function} 防抖后的函数
         */
        debounce: (func, delay) => {
            let timer;
            return function (...args) {
                clearTimeout(timer);
                timer = setTimeout(() => func.apply(this, args), delay);
            };
        },

        /**
         * 带重试机制的资源加载
         * @param {Function} loaderFn - 返回Promise的加载函数
         * @param {number} maxRetries - 最大重试次数
         * @param {number} delay - 重试间隔(毫秒)
         * @returns {Promise} 加载结果
         */
        loadWithRetry: async (loaderFn, maxRetries = config.retryAttempts, delay = config.retryDelay) => {
            for (let i = 0; i < maxRetries; i++) {
                try {
                    return await loaderFn();
                } catch (error) {
                    if (i === maxRetries - 1) {
                        throw error;
                    }
                    await new Promise(resolve => setTimeout(resolve, delay));
                }
            }
        }
    };

    // ========================
    // 模块1: 非首屏资源懒加载
    // ========================
    class LazyLoader {
        static init() {
            if (!config.lazyLoad.enabled) return;
            if (!window.IntersectionObserver) {
                logger.warn('IntersectionObserver not supported. Lazy loading disabled.');
                return;
            }

            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        this.loadElement(entry.target);
                        observer.unobserve(entry.target);
                    }
                });
            }, {
                rootMargin: config.lazyLoad.rootMargin,
                threshold: 0.01 // 只要有一小部分可见就触发
            });

            // 观察所有标记为懒加载的元素
            document.querySelectorAll(config.lazyLoad.selector).forEach(el => observer.observe(el));
        }

        /**
         * 根据元素类型加载其资源
         * @param {Element} element - 要加载的DOM元素
         */
        static loadElement(element) {
            const src = element.dataset.src || element.dataset.lazySrc;
            const href = element.dataset.href || element.dataset.lazyHref;

            if (src) {
                // 处理图片、脚本等
                if (element.tagName === 'IMG') {
                    element.src = src;
                } else if (element.tagName === 'SCRIPT') {
                    element.src = src;
                    element.async = true;
                }
                // 可以扩展更多类型
            } else if (href) {
                // 处理样式表
                if (element.tagName === 'LINK' && element.rel === 'stylesheet') {
                    element.href = href;
                }
            }

            // 加载完成后,可以添加一个类名表示已加载
            element.classList.add('loaded');
            logger.debug(`Lazy loaded: ${src || href}`);
        }
    }

    // ========================
    // 模块2: 事件处理器优化
    // ========================
    class EventOptimizer {
        static init() {
            // 优化滚动事件
            window.addEventListener('scroll', utils.throttle(() => {
                logger.debug('Throttled scroll event');
                // 在这里可以触发滚动相关的逻辑,例如视差效果、吸顶导航等
                // 但避免在此处进行复杂的DOM操作
            }, config.throttleDelay));

            // 优化窗口大小变化事件
            window.addEventListener('resize', utils.debounce(() => {
                logger.debug('Debounced resize event');
                // 响应式布局调整
            }, config.debounceDelay));
        }
    }

    // ========================
    // 模块3: 硬件加速优化 (谨慎使用)
    // ========================
    class GpuAccelerator {
        static init() {
            if (!config.hardwareAcceleration.enabled) return;
            if (!window.IntersectionObserver) {
                logger.warn('GPU Acceleration requires IntersectionObserver.');
                return;
            }

            const className = 'gpu-accelerate';
            const style = document.createElement('style');
            style.textContent = `
                .${className} {
                    /* 使用 translate3d 而非 translateZ(0) 是更常见的做法 */
                    transform: translate3d(0, 0, 0);
                    /* will-change 是提示,应动态添加 */
                    /* will-change: transform; */
                }
            `;
            document.head.appendChild(style);

            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    const target = entry.target;
                    if (entry.isIntersecting) {
                        // 元素进入视口,添加硬件加速类和 will-change
                        target.classList.add(className);
                        target.style.willChange = 'transform';
                    } else {
                        // 元素离开视口,移除 will-change 以释放资源
                        target.style.willChange = 'auto';
                        // 保留类名以防它很快回来,或根据需要移除
                        // target.classList.remove(className);
                    }
                });
            }, {
                rootMargin: '50px', // 在视口外50px就开始准备
                threshold: 0
            });

            document.querySelectorAll(config.hardwareAcceleration.selector).forEach(el => observer.observe(el));
        }
    }

    // ========================
    // 模块4: Web Worker 管理器 (可选)
    // ========================
    class WorkerManager {
        static init() {
            if (!config.webWorker.enabled || !window.Worker) {
                logger.warn('Web Worker is disabled or not supported.');
                return;
            }

            // 如果用户没有提供自定义任务,则不创建Worker
            if (typeof config.webWorker.customTask !== 'function') {
                logger.info('No custom task provided for Web Worker.');
                return;
            }

            // 将自定义任务的字符串表示形式注入Worker
            const workerCode = `
                self.onmessage = function(e) {
                    const result = (${config.webWorker.customTask.toString()})(e.data);
                    self.postMessage(result);
                };
            `;

            try {
                const blob = new Blob([workerCode], { type: 'application/javascript' });
                const worker = new Worker(URL.createObjectURL(blob));

                worker.onmessage = (e) => {
                    logger.info('Web Worker result:', e.data);
                    // 在这里处理结果,例如更新UI
                };

                worker.onerror = (error) => {
                    logger.error('Web Worker error:', error);
                };

                // 示例:发送一个任务
                // worker.postMessage(1000000);

                // 将worker实例暴露,以便外部可以使用
                window.PerformanceWorker = worker;

            } catch (error) {
                logger.error('Failed to create Web Worker:', error);
            }
        }
    }

    // ========================
    // 模块5: DOM变化监听器
    // ========================
    class DomObserver {
        static init() {
            const observer = new MutationObserver(utils.throttle(() => {
                // 当有新元素被添加时,重新初始化懒加载和GPU加速,以覆盖动态内容
                if (config.lazyLoad.enabled) {
                    document.querySelectorAll(config.lazyLoad.selector)
                        .forEach(el => {
                            if (!el.dataset.observed) {
                                LazyLoader.init();
                                el.dataset.observed = 'true';
                            }
                        });
                }
                if (config.hardwareAcceleration.enabled) {
                    document.querySelectorAll(config.hardwareAcceleration.selector)
                        .forEach(el => {
                            if (!el.dataset.observed) {
                                GpuAccelerator.init();
                                el.dataset.observed = 'true';
                            }
                        });
                }
            }, 200)); // 避免过于频繁地触发

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        }
    }

    // ========================
    // 主应用 - 初始化所有模块
    // ========================
    class App {
        static init() {
            logger.info('Performance Optimization Toolkit initialized.');

            // 按需初始化各个模块
            LazyLoader.init();
            EventOptimizer.init();
            GpuAccelerator.init();
            WorkerManager.init();
            DomObserver.init(); // 必须在最后,以监听其他模块创建的元素

            // 清理
            window.addEventListener('beforeunload', () => {
                logger.debug('Cleaning up...');
                if (window.PerformanceWorker) {
                    window.PerformanceWorker.terminate();
                }
            });
        }
    }

    // ========================
    // 启动应用
    // ========================
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', App.init);
    } else {
        App.init();
    }

    // ========================
    // 对外API - 允许外部调用
    // ========================
    // 将核心工具暴露到全局,方便在页面其他脚本中使用
    window.PerformanceUtils = {
        throttle: utils.throttle,
        debounce: utils.debounce,
        loadWithRetry: utils.loadWithRetry
    };

})();