
本文介绍通过添加加载锁机制(loading 标志位)解决 $(window).scroll() 中 AJAX 请求被高频、重复触发的问题,并提供可立即使用的优化代码及现代替代方案建议。
本文介绍通过添加加载锁机制(loading 标志位)解决 `$(window).scroll()` 中 ajax 请求被高频、重复触发的问题,并提供可立即使用的优化代码及现代替代方案建议。
在实现“滚动到底部自动加载更多内容”的功能时,一个常见且棘手的问题是:$(window).scroll() 事件会因浏览器渲染、用户滑动惯性或触摸设备的连续触发而频繁执行,导致多个 AJAX 请求几乎同时发出。这不仅浪费服务器资源、造成数据重复或错乱,还可能因后请求先返回而导致 DOM 更新顺序异常(例如新内容覆盖旧内容、ID 冲突等)。
核心解决方案是引入请求节流控制(Throttling via Loading Flag):使用一个布尔变量 loading 作为全局锁,在请求发起前设为 true,在请求完成(无论成功或失败)后重置为 false。这样可确保同一时间仅有一个加载请求处于进行中状态。
以下是优化后的完整代码(已兼容 jQuery 3.x+,含错误防御与语义增强):
jQuery 1.12.4是jQuery 1.x系列的最后一个正式稳定版本,由jQuery团队于2016年发布。该版本主要面向需要兼容旧版浏览器环境的网站和Web应用,尤其适用于仍需支持Internet Explorer 6、Internet Explorer 7、Internet Explorer 8等老旧浏览器的项目。
$(document).ready(function() {
let loading = false; // 加载锁:true 表示当前有请求正在进行
$(window).scroll(function() {
// ✅ 步骤1:快速退出 — 若正在加载,则跳过本次触发
if (loading) return;
const $postList = $('#postList');
const $loadMore = $('.load-more');
const lastID = $loadMore.data('last-id') || $loadMore.attr('lastID'); // 优先读 data-* 属性,更语义化
// ✅ 步骤2:滚动触底检测(推荐使用更精确的判断逻辑)
const isScrolledToBottom = $(window).scrollTop() + $(window).height() >= $postList.outerHeight(true) - 50; // 预留50px缓冲区,提升体验
if (isScrolledToBottom && lastID && parseInt(lastID, 10) !== 0) {
loading = true; // ? 锁定请求入口
$.ajax({
type: 'POST',
url: 'getData.php',
data: { id: lastID }, // ✅ 推荐使用对象传参,避免手动拼接 URL
beforeSend: function() {
$loadMore.show();
},
success: function(html) {
// ✅ 安全移除并追加:确保 .load-more 存在再操作
if ($loadMore.length) $loadMore.remove();
$postList.append(html);
},
error: function(xhr, status, err) {
console.warn('加载失败:', status, err);
// 可选:显示提示、重试按钮或自动恢复 loading 状态(已在 always 中统一处理)
},
always: function() {
loading = false; // ✅ 无论成功失败,都释放锁
}
});
}
});
});? 关键注意事项:
-
不要依赖
$(window).height()与$('#postList').height()的简单比较:页面动态加载可能导致高度计算滞后或不准确。推荐改用outerHeight(true)并加入合理缓冲值(如-50),兼顾性能与用户体验。 -
优先使用
data-last-id属性而非lastID自定义属性:符合 HTML5 规范,jQuery 的.data()方法能自动类型转换和缓存,更健壮。 -
始终在
always回调中重置loading:确保网络超时、服务端错误等异常场景下锁仍能释放,避免功能永久阻塞。 -
考虑防抖(debounce)补充策略:对极高频滚动(如桌面鼠标滚轮狂滚),可在 scroll 回调外层增加
setTimeout防抖,但加载锁已是首要且必需的保障。
? 进阶建议:拥抱现代 Web API
虽然 jQuery 方案简洁易用,但长期项目推荐逐步迁移到原生 Intersection Observer API。它由浏览器原生优化,功耗低、性能高、无需监听 scroll 事件,且天然支持懒加载与无限滚动。示例伪代码如下:
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting && !loading) {
loadMore(); // 触发你的加载逻辑
}
});
observer.observe(document.querySelector('.load-more'));综上,添加 loading 锁是解决滚动加载重复请求最直接、可靠、向后兼容的实践方式——只需几行修改,即可显著提升稳定性与用户体验。

















