每个()循环中的jQuery AJAX解决方案

我注意到当我在.each()循环中使用jQuery中的AJAX时遇到问题。 脚本执行时,仅更新数据库中的第一条记录。

这是我的脚本:

function save(){ var _userTypeId; var _userTypeName; var _isDeleted; var request; $("tr.recUserType").each(function(){ $this = $(this); _userTypeId = $this.find("#userTypeId").html(); _userTypeName = $this.find("#userTypeName").val(); _isDeleted = $this.find("#isDeleted").val(); request = $.ajax({ url: "save.php", type: "POST", data: {userTypeId: _userTypeId, userTypeName: _userTypeName, isDeleted: _isDeleted} }); }); request.done(function(){ document.location.reload(); }); request.fail(function(){ alert("Request Failed!"); }); } 

以及save.php的内容:

 <?php include_once "globals.php"; dbConnect(); $isExisting = mysql_query("SELECT COUNT(userTypeId) AS userCount FROM userType WHERE userTypeId='".$_POST['userTypeId']."';"); $result = mysql_fetch_array($isExisting); //original: if(!$result['userCount'] = 0)  

我已经读过我可以选择使用同步而不是异步,但我也读过它不是一个好习惯。

那么我如何实际异步完成并修复问题呢?

jQuery的$ .ajax()返回一个jQuery XMLHttpRequest对象(“jqXHR”)。 您将此对象存储到“响应”变量中。

你的问题是范围。 您将所有N个jqXHR存储到相同的“请求”变量中。 在循环结束时,“request”仅指向最后一个jqXHR,因此只有在LAST请求完成时才会调用.done()。

正如Karl Anderson指出的那样,你应该将所有的jqXHR存储到一个数组中,然后一旦所有的jqXHR完成[异步]就执行一个回调。

 var XHRs = []; // ... $("tr.recUserType").each(function() { $this = $(this); _userTypeId = $this.find("#userTypeId").html(); _userTypeName = $this.find("#userTypeName").val(); _isDeleted = $this.find("#isDeleted").val(); XHRs.push($.ajax({ url: "save.php", type: "POST", data: {userTypeId: _userTypeId, userTypeName: _userTypeName, isDeleted: _isDeleted} })); }); $.when(XHRs).then(function() { document.location.reload(); }); 

另外,避免使用$ .ajax()的“async:false”的美味诱惑。 浏览器将被强制挂起,直到请求完成,这很糟糕。 您几乎总是可以异步完成$ .ajax()调用; 它可能需要一些狡猾,但肯定会变得更好。

您的问题出在这段代码中:

 request.done(function(){ document.location.reload(); }); 

由于操作是异步的,因此在保存完成之前执行此行,因此在第一次保存完成后,它将执行done逻辑。

您需要创建一个延迟对象数组,然后等待它们全部执行,然后使用jQuery .when()/.then()函数继续执行逻辑。

这是一个之前的StackOverflow问题,详细说明了如何设置这种情况。 当每个完成触发function时,请阅读jQuery的接受答案。

这里发生了一些事情。

  1. 通过在循环中重用request变量(在循环外部作用域),循环的每次迭代都会分配一个新对象来请求,覆盖那里的内容。 这意味着您只需为最后一次迭代设置响应处理程序。

  2. 您的request.done方法重新加载页面,实际上将暂停其他请求和…

  3. 如@Sean所述,您正在为循环的每次迭代查找相同的userTypeId