Webp图片加载优化

Optimize image loading by adding lazy loading, WebP support, and concurrent requests.

// ==UserScript==
// @name         Webp图片加载优化
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Optimize image loading by adding lazy loading, WebP support, and concurrent requests.
// @author       KiwiFruit
// @match        *://*/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 检查浏览器是否支持WebP格式
    function supportsWebP(callback) {
        const webP = new Image();
        webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
                   'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
        webP.onload = webP.onerror = () => callback(webP.height === 2);
    }

    // 替换图片元素的src属性为对应的WebP版本
    function replaceWithWebP(imageElement, src) {
        supportsWebP((supports) => {
            if (supports) {
                // 尝试将图片路径转换为WebP格式
                const webpSrc = src.replace(/\.(jpg|jpeg|png)$/, '.webp');
                fetch(webpSrc)
                    .then(response => {
                        // 如果响应成功,则设置图片的src为WebP版本
                        if (response.ok) {
                            imageElement.src = webpSrc;
                        } else {
                            // 如果响应失败,则回退到原始图片路径
                            imageElement.src = src;
                        }
                    })
                    .catch(() => {
                        // 在fetch请求出错的情况下,也回退到原始图片路径
                        imageElement.src = src;
                    });
            } else {
                // 如果不支持WebP,则直接使用原始图片路径
                imageElement.src = src;
            }
        });
    }

    // 并发加载一组图片URL
    function loadImages(imageUrls) {
        return Promise.all(imageUrls.map(url =>
            new Promise((resolve, reject) => {
                const img = new Image();
                img.src = url;
                img.onload = () => resolve(img);
                img.onerror = () => reject(new Error(`Failed to load ${url}`));
            })
        ));
    }

    // 设置动态加载机制
    function setupDynamicLoading(images) {
        let observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const img = entry.target;
                    observer.unobserve(img);
                    replaceWithWebP(img, img.getAttribute('data-src'));
                }
            });
        }, { threshold: 0.1 });

        images.forEach(img => observer.observe(img));
    }

    // 预加载首屏可见区域内的图片
    function preloadFirstScreenImages(images) {
        const visibleImages = Array.from(images).filter(img => {
            const rect = img.getBoundingClientRect();
            return rect.top >= 0 && rect.bottom <= window.innerHeight;
        });

        const imageUrls = visibleImages.map(img => img.getAttribute('data-src'));
        loadImages(imageUrls).then(() => setupDynamicLoading(images));
    }

    // 监听DOMContentLoaded事件确保DOM完全构建后再执行
    document.addEventListener('DOMContentLoaded', () => {
        const images = document.querySelectorAll('img[data-src]');

        if (images.length > 0) {
            preloadFirstScreenImages(images);
        }
    });

})();