Ultimate Web Optimizer

全面的网页性能优化方案(含懒加载/预加载/预连接)

当前为 2025-05-26 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Ultimate Web Optimizer
// @namespace    https://greasyfork.org/zh-CN/users/1474228-moyu001
// @version      1.0
// @description  全面的网页性能优化方案(含懒加载/预加载/预连接)
// @author       moyu001
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_log
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ========================
    // 配置中心
    // ========================
    const config = {
        debug: false,  // 开启调试日志
        features: {
            lazyLoad: {  // 图片懒加载
                enabled: true,
                minSize: 100,     // 最小处理尺寸(px)
                rootMargin: '200px',  // 提前加载距离
                skipHidden: true  // 跳过隐藏图片
            },
            preconnect: {  // 智能预连接
                enabled: true,
                whitelist: [  // 白名单优化
                    'fonts.gstatic.com',
                    'cdnjs.cloudflare.com',
                    'unpkg.com',
                    'ajax.googleapis.com',
                    'maxcdn.bootstrapcdn.com',
                    'code.jquery.com',
                    'kit.fontawesome.com',
                    'fonts.googleapis.cn',
                    'fonts.loli.net',
                    'cdn.jsdelivr.net',
                    'cdn.bootcdn.net',
                    'cdn.bootcss.com',
                    'libs.baidu.com',
                    'cdn.staticfile.org',
                    'lf3-cdn-tos.bytecdntp.com',
                    'unpkg.zhimg.com',
                    'npm.elemecdn.com',
                    'g.alicdn.com'
                ],
                maxConnections: 5  // 最大预连接数
            },
            preload: {  // 资源预加载
                enabled: true,
                types: ['css', 'js', 'woff2'],  // 预加载类型
                maxPreloads: 5  // 最大预加载数
            },
            layout: {  // 布局稳定性
                stableImages: true,
                stableIframes: true
            }
        }
    };

    // ========================
    // 核心优化模块
    // ========================

    // 图片懒加载系统
    const initLazyLoad = () => {
        if (!config.features.lazyLoad.enabled) return;

        const isLazyCandidate = (img) => {
            if (img.loading === 'eager') return false;
            if (img.complete) return false;
            if (img.src.startsWith('data:')) return false;
            if (config.features.lazyLoad.skipHidden &&
                window.getComputedStyle(img).display === 'none') return false;

            const rect = img.getBoundingClientRect();
            return rect.width > config.features.lazyLoad.minSize &&
                   rect.height > config.features.lazyLoad.minSize;
        };

        const processImage = (img) => {
            if (!img.dataset.src && img.src) {
                img.dataset.src = img.src;
                img.removeAttribute('src');
            }
            if (img.srcset && !img.dataset.srcset) {
                img.dataset.srcset = img.srcset;
                img.removeAttribute('srcset');
            }
            return img;
        };

        // 现代浏览器实现
        if ('IntersectionObserver' in window) {
            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        const img = entry.target;
                        if (img.dataset.src) img.src = img.dataset.src;
                        if (img.dataset.srcset) img.srcset = img.dataset.srcset;
                        observer.unobserve(img);
                    }
                });
            }, {
                rootMargin: config.features.lazyLoad.rootMargin,
                threshold: 0.01
            });

            // 初始图片
            document.querySelectorAll('img').forEach(img => {
                if (isLazyCandidate(img)) {
                    observer.observe(processImage(img));
                }
            });

            // 动态加载监听
            new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeName === 'IMG' && isLazyCandidate(node)) {
                            observer.observe(processImage(node));
                        }
                    });
                });
            }).observe(document.body, {
                childList: true,
                subtree: true
            });
        } else {
            // 兼容模式实现
            const checkVisible = throttle(() => {
                document.querySelectorAll('img').forEach(img => {
                    if (isLazyCandidate(img) && !img.src) {
                        const rect = img.getBoundingClientRect();
                        if (rect.top < window.innerHeight +
                            parseInt(config.features.lazyLoad.rootMargin)) {
                            if (img.dataset.src) img.src = img.dataset.src;
                            if (img.dataset.srcset) img.srcset = img.dataset.srcset;
                        }
                    }
                });
            }, 200);
            window.addEventListener('scroll', checkVisible);
            checkVisible();
        }
    };

    // 智能预连接系统
    const initSmartPreconnect = () => {
        if (!config.features.preconnect.enabled) return;

        const processed = new Set();
        const whitelist = config.features.preconnect.whitelist;

        const doPreconnect = (hostname) => {
            if (processed.size >= config.features.preconnect.maxConnections) return;
            if (processed.has(hostname)) return;

            const link = document.createElement('link');
            link.rel = 'preconnect';
            link.href = `https://${hostname}`;
            document.head.appendChild(link);
            processed.add(hostname);

            if (config.debug) {
                console.log('[Preconnect] 已连接:', hostname);
            }
        };

        const scanResources = () => {
            const resources = [
                ...document.querySelectorAll('script[src], link[href], img[src]')
            ];

            resources.forEach(el => {
                try {
                    const url = new URL(el.src || el.href);
                    const matched = whitelist.find(domain =>
                        url.hostname.endsWith(domain)
                    );
                    if (matched) {
                        doPreconnect(url.hostname);
                    }
                } catch {}
            });
        };

        // 三级触发机制
        scanResources(); // 立即扫描
        setTimeout(scanResources, 2000); // 捕获异步资源
        new MutationObserver(() => {
            setTimeout(scanResources, 100);
        }).observe(document.body, {
            childList: true,
            subtree: true
        });
    };

    // 资源预加载系统
    const initResourcePreload = () => {
        if (!config.features.preload.enabled) return;

        const processed = new Set();
        const types = config.features.preload.types;
        const max = config.features.preload.maxPreloads;

        const shouldPreload = (url) => {
            const ext = url.split('.').pop().toLowerCase();
            return types.includes(ext);
        };

        const doPreload = (url, asType) => {
            if (processed.size >= max) return;
            if (processed.has(url)) return;

            const link = document.createElement('link');
            link.rel = 'preload';
            link.as = asType;
            link.href = url;

            // 添加type属性
            if (asType === 'font') {
                link.setAttribute('crossorigin', 'anonymous');
                if (url.includes('.woff2')) {
                    link.type = 'font/woff2';
                } else if (url.includes('.woff')) {
                    link.type = 'font/woff';
                }
            } else if (asType === 'script') {
                link.type = 'text/javascript';
            } else if (asType === 'style') {
                link.type = 'text/css';
            }

            document.head.appendChild(link);
            processed.add(url);

            if (config.debug) {
                console.log('[Preload] 已预加载:', url);
            }
        };

        const processFont = (cssUrl, fontUrl) => {
            try {
                const absoluteUrl = new URL(fontUrl, cssUrl).href;
                if (fontUrl.startsWith('data:')) return; // 跳过数据URI
                if (shouldPreload(absoluteUrl)) {
                    doPreload(absoluteUrl, 'font');
                }
            } catch (e) {
                if (config.debug) {
                    console.warn('[Preload] 字体解析失败:', fontUrl, e);
                }
            }
        };

        const scanResources = () => {
            // 处理CSS
            document.querySelectorAll('link[rel="stylesheet"]').forEach(link => {
                const cssUrl = link.href;
                if (cssUrl && shouldPreload(cssUrl)) {
                    doPreload(cssUrl, 'style');

                    // 解析CSS中的字体
                    fetch(cssUrl)
                        .then(res => res.text())
                        .then(text => {
                            const fontUrls = text.match(/url\(["']?([^)"']+\.woff2?)["']?\)/gi) || [];
                            fontUrls.forEach(fullUrl => {
                                const cleanUrl = fullUrl.replace(/url\(["']?|["']?\)/g, '');
                                processFont(cssUrl, cleanUrl);
                            });
                        })
                        .catch(e => {
                            if (config.debug) {
                                console.warn('[Preload] CSS获取失败:', cssUrl, e);
                            }
                        });
                }
            });

            // 处理JS
            document.querySelectorAll('script[src]').forEach(script => {
                const src = script.src;
                if (src && shouldPreload(src)) {
                    doPreload(src, 'script');
                }
            });
        };

        scanResources();
        new MutationObserver(() => {
            setTimeout(scanResources, 100);
        }).observe(document.body, {
            childList: true,
            subtree: true
        });
    };

    // 布局稳定性优化
    const initLayoutStabilization = () => {
        const styles = [];

        if (config.features.layout.stableImages) {
            styles.push(`
                img:not([width]):not([height]) {
                    min-height: 1px;
                }
                @supports (aspect-ratio: 1/1) {
                    img:not([width]):not([height]) {
                        aspect-ratio: attr(width) / attr(height);
                    }
                }
            `);
        }

        if (config.features.layout.stableIframes) {
            styles.push(`
                iframe:not([width]):not([height]) {
                    width: 100%;
                    height: auto;
                    aspect-ratio: 16/9;
                }
            `);
        }

        if (styles.length) {
            const style = document.createElement('style');
            style.textContent = styles.join('\n');
            document.head.appendChild(style);
        }
    };

    // ========================
    // 工具函数
    // ========================
    function throttle(func, limit) {
        let inThrottle;
        return function() {
            if (!inThrottle) {
                func.apply(this, arguments);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }

    // ========================
    // 初始化系统
    // ========================
    document.addEventListener('DOMContentLoaded', () => {
        initSmartPreconnect();
        initResourcePreload();
        initLazyLoad();
        initLayoutStabilization();

        if (config.debug) {
            console.groupCollapsed('[Optimizer] 初始化报告');
            console.log('激活功能:', Object.entries(config.features)
                .filter(([_, v]) => v.enabled !== false)
                .map(([k]) => k));
            console.log('预连接白名单:', config.features.preconnect.whitelist);
            console.log('预加载类型:', config.features.preload.types);
            console.groupEnd();
        }
    });
})();