Ajax异步请求重复发送问题:async设为true时触发两次请求
解决Ajax异步请求重复发送的问题
嘿,我来帮你排查这个异步请求重复发送的问题——这种情况大多和事件重复绑定或者表单默认提交没完全阻止有关,咱们一步步拆解:
核心原因分析
1. 事件委托被重复绑定
你用了$(document).on('submit', 'form', ...)这种事件委托方式,如果这段初始化代码被执行了多次(比如页面局部刷新后脚本被重新加载),就会给表单的submit事件绑定多个处理函数。每次触发提交时,addTask()就会被调用多次,自然就发了两次Ajax请求。
而同步模式(async: false)下,因为请求是阻塞的,第二次触发的函数会等第一次完成后才执行,浏览器可能在阻塞期间拦截了重复提交,所以没暴露问题。
2. 表单默认提交没被彻底阻止
虽然你在函数里返回了false,但结合事件委托的机制,有时候事件冒泡或者其他因素会导致默认的表单提交行为没被完全阻断,浏览器会额外触发一次提交,进而重复调用你的Ajax逻辑。
具体解决办法
办法一:确保事件只绑定一次
要么用one()代替on(),确保事件只绑定一次;要么先解绑再绑定,避免重复:
// 方式1:用one(),仅绑定一次submit事件 $(document).ready(function() { $(document).one('submit', 'form', function(e) { e.preventDefault(); // 显式阻止默认行为 showBusyIndicator(); addTask(); }); }); // 方式2:先解绑再绑定,适合需要动态更新表单的场景 $(document).ready(function() { $(document).off('submit', 'form').on('submit', 'form', function(e) { e.preventDefault(); showBusyIndicator(); addTask(); }); });
办法二:显式阻止默认行为+事件冒泡
别只依赖return false,直接调用e.preventDefault()和e.stopPropagation(),彻底阻断表单的默认提交和事件冒泡:
$(document).ready(function() { $(document).on('submit', 'form', function(e) { e.preventDefault(); // 阻止表单默认提交(关键) e.stopPropagation(); // 阻止事件向上冒泡(避免父元素的事件触发) showBusyIndicator(); addTask(); // 这里不需要return false了,已经显式阻断了默认行为 }); });
办法三:请求期间禁用提交按钮
在Ajax发起后暂时禁用提交按钮,防止用户重复点击或者事件重复触发,请求完成后再恢复:
function addTask() { // 假设你的提交按钮id是submitBtn,先禁用 const submitBtn = $('#submitBtn'); submitBtn.prop('disabled', true); let newTask = new Task( $("#taskSummary").val(), $("#taskDescription").val(), $("#taskDueTo").val() ); $.ajax({ url: apiHost + "/task/add/", headers: { "contentType": "application/json" }, type: "POST", async: true, dataType: "json", data: JSON.stringify(newTask), complete: function (xhr) { hideBusyIndicator(); // 请求完成后重新启用按钮 submitBtn.prop('disabled', false); if (xhr.status === 201) { closeAddTaskForm(); } else { alert(xhr.status); } }, }); }
额外排查小技巧
- 打开浏览器开发者工具的Network标签,看看两次请求的发起者是脚本还是浏览器的默认提交——如果是后者,说明默认行为没阻止成功;如果是前者,那就是事件重复绑定的问题。
- 检查页面里有没有多个相同的
<form>元素,事件委托可能匹配到多个表单,导致多次触发处理函数。
内容的提问来源于stack exchange,提问作者Maciej Kuliński
相关产品推荐
相关产品推荐

