您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Optimize resource loading by adding lazy loading, WebP support, concurrent requests, and more.
// ==UserScript== // @name WebP加载优化(此脚本转为图片加载而设计) // @namespace http://tampermonkey.net/ // @version 1.3 // @description Optimize resource loading by adding lazy loading, WebP support, concurrent requests, and more. // @author KiwiFruit // @match *://*/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // ================== 配置参数 ================== const CONFIG = { CONCURRENT_BATCH_SIZE: 10, // 每批次并发加载资源数 PRELOAD_VISIBLE_THRESHOLD: 0.1, // IntersectionObserver 的阈值 FALLBACK_RETRY_TIMES: 2, // 回退重试次数 WEBP_FALLBACK_TIMEOUT: 3000, // WebP加载超时时间(ms) USE_SKELETON_SCREEN: true, // 是否启用骨架屏(CSS动画) }; // ================== 全局变量 ================== let webpSupported = null; // WebP 支持性缓存 let resourceQueue = []; // 资源队列 let isProcessingQueue = false; // ================== WebP 支持性检测 ================== function checkWebPSupport() { if (webpSupported !== null) return Promise.resolve(webpSupported); return new Promise((resolve) => { const webP = new Image(); webP.src = 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEADsD+JaQAAAB8'; webP.onload = webP.onerror = () => { webpSupported = webP.height === 2; resolve(webpSupported); }; }); } // ================== 替换为 WebP 格式 ================== function replaceWithWebP(imageElement, src) { checkWebPSupport().then(supported => { if (supported) { // 直接替换 URL,无需额外 fetch imageElement.src = src.replace(/\.(jpg|jpeg|png)$/i, '.webp'); } else { imageElement.src = src; } }).catch(() => { imageElement.src = src; }); } // ================== 图片加载器 ================== function fetchImage(url, retries = CONFIG.FALLBACK_RETRY_TIMES) { return new Promise((resolve, reject) => { const img = new Image(); img.src = url; const timeout = setTimeout(() => { img.onerror = img.onload = null; if (retries > 0) { console.warn(`Retrying image: ${url}`); fetchImage(url, retries - 1).then(resolve).catch(reject); } else { reject(new Error(`Failed to load image: ${url}`)); } }, CONFIG.WEBP_FALLBACK_TIMEOUT); img.onload = () => { clearTimeout(timeout); if (CONFIG.USE_SKELETON_SCREEN) { img.classList.add('loaded'); } resolve(img); }; img.onerror = () => { clearTimeout(timeout); reject(new Error(`Image load error: ${url}`)); }; }); } // ================== 脚本加载器 ================== function loadScript(url, retries = CONFIG.FALLBACK_RETRY_TIMES) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = url; const timeout = setTimeout(() => { script.onerror = script.onload = null; if (retries > 0) { console.warn(`Retrying script: ${url}`); loadScript(url, retries - 1).then(resolve).catch(reject); } else { reject(new Error(`Failed to load script: ${url}`)); } }, CONFIG.WEBP_FALLBACK_TIMEOUT); script.onload = () => { clearTimeout(timeout); resolve(script); }; script.onerror = () => { clearTimeout(timeout); reject(new Error(`Script load error: ${url}`)); }; document.head.appendChild(script); }); } // ================== 并发加载资源 ================== async function loadResourcesInBatches(resources) { if (isProcessingQueue) return; isProcessingQueue = true; for (let i = 0; i < resources.length; i += CONFIG.CONCURRENT_BATCH_SIZE) { const batch = resources.slice(i, i + CONFIG.CONCURRENT_BATCH_SIZE); await Promise.allSettled(batch.map(resource => { if (resource.type === 'image') { return fetchImage(resource.url).catch(err => { console.error('Image load failed:', err.message); return null; }); } else if (resource.type === 'script') { return loadScript(resource.url).catch(err => { console.error('Script load failed:', err.message); return null; }); } })); } isProcessingQueue = false; } // ================== 懒加载资源 ================== function setupLazyLoading(resources) { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const element = entry.target; observer.unobserve(element); if (element.dataset.type === 'image') { replaceWithWebP(element, element.dataset.src); resourceQueue.push({ type: 'image', url: element.src }); } else if (element.dataset.type === 'script') { resourceQueue.push({ type: 'script', url: element.dataset.src }); } } }); // 触发并发加载 if (!isProcessingQueue) { loadResourcesInBatches(resourceQueue); resourceQueue = []; } }, { threshold: CONFIG.PRELOAD_VISIBLE_THRESHOLD }); resources.forEach(resource => observer.observe(resource)); } // ================== 预加载首屏资源 ================== function preloadFirstScreenResources(resources) { const visibleResources = Array.from(resources).filter(resource => { const rect = resource.getBoundingClientRect(); return rect.top >= 0 && rect.bottom <= window.innerHeight; }); visibleResources.forEach(resource => { if (resource.dataset.type === 'image') { replaceWithWebP(resource, resource.dataset.src); resourceQueue.push({ type: 'image', url: resource.src }); } else if (resource.dataset.type === 'script') { resourceQueue.push({ type: 'script', url: resource.dataset.src }); } }); // 立即加载首屏资源 if (resourceQueue.length > 0) { loadResourcesInBatches(resourceQueue); resourceQueue = []; } // 绑定懒加载 setupLazyLoading(resources); } // ================== 初始化入口 ================== document.addEventListener('DOMContentLoaded', async () => { const resources = document.querySelectorAll('[data-src]'); if (resources.length === 0) return; // 预加载首屏资源 preloadFirstScreenResources(resources); }); // ================== CSS 动画(骨架屏) ================== const style = document.createElement('style'); style.textContent = ` img.lazyload { opacity: 0.3; transition: opacity 0.3s ease-in-out; } img.lazyload.loaded { opacity: 1; } `; document.head.appendChild(style); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址