JavaScript无限滚动+懒加载:如何优先处理HTTP请求(连接被耗尽)
嘿,这个场景太常见了——浏览器同域并发连接数通常限制在6个左右,你一次性加载6篇文章,每篇里的图片触发懒加载时瞬间占满所有连接,确实会导致后续请求(比如下一批文章的API请求)被阻塞。给你几个实用的解决方案,按落地成本和效果排序:
1. 分批触发图片懒加载(最推荐的前端方案)
核心思路是不让所有进入视口的图片同时发起请求,而是分批次处理,比如每次只加载2-3张,等这批加载完成后再处理下一批。这样能避免瞬间占满浏览器的并发连接池。
如果是自己实现的懒加载(用IntersectionObserver),可以加个请求队列来控制批次:
const imageLoadQueue = []; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 把进入视口的图片加入队列,停止监听 imageLoadQueue.push(entry.target); observer.unobserve(entry.target); } }); // 开始处理队列 processImageQueue(); }); // 批量处理队列,每次加载2张 function processImageQueue() { if (imageLoadQueue.length === 0) return; const batch = imageLoadQueue.splice(0, 2); batch.forEach(img => { // 替换真实图片地址 img.src = img.dataset.src; // 一张加载完成后,自动处理下一批 img.onload = () => processImageQueue(); // 处理加载失败的情况,避免队列卡住 img.onerror = () => processImageQueue(); }); } // 初始化监听所有懒加载图片 document.querySelectorAll('.lazy').forEach(img => observer.observe(img));
如果你用的是第三方懒加载插件(比如lozad.js、lazyload.js),可以看看插件有没有自带的batch或者threshold配置,很多成熟插件已经支持分批加载的功能,直接配置即可。
2. 启用HTTP/2(一劳永逸的后端方案)
HTTP/1.1的并发连接限制是导致这个问题的根源之一,而HTTP/2支持多路复用——同一个TCP连接可以同时传输多个请求和响应,不会再受6个连接的限制。
如果你的服务器支持HTTP/2(现在主流的Nginx、Apache、CDN都支持),只需要开启这个配置就行,前端代码完全不用改。开启后,即使一次性触发6个图片请求,也不会占满连接,其他API请求依然能正常发起。
3. 利用原生懒加载的优先级控制
现代浏览器支持原生的loading="lazy"懒加载,同时还支持fetchpriority属性来指定请求优先级:
<!-- 视口内的图片设为高优先级 --> <img data-src="article-main.jpg" loading="lazy" fetchpriority="high" class="lazy"> <!-- 视口外的图片设为低优先级 --> <img data-src="article-side.jpg" loading="lazy" fetchpriority="low" class="lazy">
浏览器会优先处理fetchpriority="high"的请求,把低优先级的图片请求延后,这样能保证关键资源(比如下一批文章的API请求)先得到连接。
注意:fetchpriority的兼容性需要确认,现代Chrome、Firefox、Edge都支持,但Safari的支持稍晚,需要根据你的用户群体判断是否适用。
4. 节流无限滚动的加载时机
有时候用户快速滚动页面会触发多次加载,导致一次性注入大量带懒加载图片的HTML。给滚动事件加个节流,让加载逻辑只在用户停止滚动一段时间后触发,减少一次性加载的文章数量:
let isLoading = false; const throttleScroll = throttle(() => { if (isLoading) return; // 距离底部100px时触发加载 if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) { isLoading = true; $.get(`/api/post/${chunkToLoadNow}/${categoryToLoad}/`, (response) => { // 追加HTML内容 $('#posts-container').append(response); isLoading = false; }); } }, 300); window.addEventListener('scroll', throttleScroll); // 简单的节流函数 function throttle(func, delay) { let lastInvokeTime = 0; return function(...args) { const now = Date.now(); if (now - lastInvokeTime >= delay) { func.apply(this, args); lastInvokeTime = now; } }; }
这样能避免短时间内注入过多内容,减少同时触发的图片请求数量。
总结
如果能修改后端配置,优先开启HTTP/2,彻底解决并发连接限制的问题;如果只能改前端,分批加载图片是最稳妥的方案,兼容性和效果都很好;原生懒加载的优先级控制适合现代浏览器环境,可以作为辅助优化手段。
内容的提问来源于stack exchange,提问作者Matt Komarnicki

