我注意到当我在.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) <-- This was a logical error
if($result['userCount'] != 0)
mysql_query("UPDATE userType SET userTypeName='".$_POST['userTypeName']."', isDeleted='".$_POST['isDeleted']."' WHERE userTypeId='".$_POST['userTypeId']."';");
else
mysql_query("INSERT INTO userType VALUES('', '".$_POST['userTypeName']."', '".$_POST['isDeleted']."');");
echo mysql_error();
dbClose();
?>
我已经读过我可以选择使用同步而不是异步,但我也读过它不是一个好习惯。
那么我如何实际异步完成并修复问题?
答案 0 :(得分:4)
jQuery的$ .ajax()返回一个jQuery XMLHttpRequest对象(“jqXHR”)。您将此对象存储到“响应”变量中。
你的问题是范围。您将jqXHR的所有 N 存储到相同的“请求”变量中。在循环结束时,“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()调用;它可能需要一些狡猾,但肯定会变得更好。
答案 1 :(得分:0)
您的问题出在这段代码中:
request.done(function(){
document.location.reload();
});
由于操作是异步的,因此在保存完成之前执行此行,因此在第一次保存完成后,它将执行done
逻辑。
您需要创建一个延迟对象数组,然后等待它们全部执行,然后再使用jQuery .when()/.then()
函数继续执行逻辑。
这是一个之前的StackOverflow问题,详细说明了如何设置这种情况。请阅读jQuery when each is completede trigger function的接受答案。
答案 2 :(得分:0)
这里发生了一些事情。
通过在循环中重新使用request
变量(在循环外部作用域),循环的每次迭代都会分配一个新对象来请求,覆盖那里的内容。这意味着您只为最后一次迭代设置响应处理程序。
您的request.done
方法重新加载页面,实际上会停止其他请求并... ...
您正在为循环的每次迭代查找相同的userTypeId
,如@Sean所述