防止重复发送 Ajax 请求的四种策略

作者:霁月

时间:2026-10-21

浏览:445

本文深入探讨防止 Ajax 重复提交的四种核心策略:独占型、贪婪型、节制型(节流)与懒惰型(去抖)。通过对比 jQuery 实现方式及知乎、游戏等实际场景,解析如何利用状态判断、abort 机制及时间控制函数解决竞态条件,提升应用性能与用户体验。

文章目录

Ajax 事件处理与状态管理基础

开发者需准确区分并正确注册 success、complete、error 及 timeout 等回调事件,若处理不当,将导致功能失效。

相较于常规流程,此场景下必须额外注册 complete 事件以处理状态恢复。

状态恢复逻辑若未妥善隔离,极易与无关代码混杂,增加维护难度。

建议采用主动查询状态(如 jQuery 示例 A、B)或封装工具函数(如示例 C、D)来规避重复操作,具体实现参考如下。

独占型与贪婪型提交策略

A. 独占型提交策略

该策略限制同一时刻仅允许存在一个提交任务,且必须等待当前任务完成后方可发起下一次提交。


module.submit = function() {
 if (this.promise_.state() === 'pending') {
 return
 }
 return this.promise_ = $.post('/api/save')
}

B. 贪婪型提交策略

允许无限制发起提交,但系统仅以最后一次操作的结果为准;即优先展示最新操作的反馈,忽略中间过程的结果。


module.submit = function() {
 if (this.promise_.state() === 'pending') {
 this.promise_.abort()
 }
 // todo
}

例如某些应用中的“喜欢/不喜欢”二态按钮,若不及时反馈,用户可能长时间注视按钮。通过即时切换按钮状态并调用 abort 取消旧请求,既能提升用户体验,又能减轻服务器负载。

节制型(节流)与懒惰型(去抖)策略

C. 节制型提交策略

无论提交频率多高,任意两次有效提交的时间间隔必须大于或等于设定的阈值,即按固定频率执行提交。


module.submit = throttle(150, function() {
 // todo
})

若客户端在 100 毫秒内发送 10 次请求,该模块仅处理其中 6 个(每 150 毫秒执行一次)。

这也是解决查询冲突的有效手段,以知乎草稿编辑为例,可观察到以下现象:

编辑器的 blur 事件触发时会立即执行保存操作;

保存按钮的 click 事件同样会立即触发保存;

当焦点位于编辑器内部且用户直接点击保存按钮时,这两个事件可能在数毫秒内连续发生,此时使用 throttle 处理是可行的方案。

此外,resize、scroll、mousemove 等高频事件处理也常广泛使用 throttle 技术。

D. 懒惰型提交策略

任意两次提交的间隔时间必须超过指定阈值,才会触发有效提交;即“不休息不干活”。


module.submit = debounce(150, function() {
 // todo
})

以知乎草稿为例,按下 Ctrl + S 可手动保存。若用户连续快速按键,程序会忽略后续操作,直至用户停止连按后才执行保存。

============

节流与去抖的实际应用场景

更多典型应用场景

方式 C 和方式 D 具有更高的通用性,适用于以下场景:

游戏中拾取高速武器时,为防止子弹在屏幕上连成直线,可使用 throttle 控制射击频率;

在弹幕射击游戏中,为防止玩家按住射击键进行无脑操作,可使用 debounce 控制发射频率;

在编译任务中,守护进程监听文件夹变化(单次编译需 2 秒),若 git checkout 等操作瞬间修改大量文件,使用 debounce 可确保编译任务仅执行一次。

方式 C 甚至可与方式 B 组合使用,例如自动完成组件(如 Google 首页搜索):

当用户快速输入文本(尤其是打字高手)时,通过 throttle 限制 keypress 事件处理频率,按指定间隔提取文本域值并立即发起新查询;

当新查询需发送但上一查询尚未返回时,可 abort 未完成的查询,并立即发送新查询。

以上内容为本文核心观点,旨在为学习与工作提供参考,感谢支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章