我正在使用嵌套 AJAX。我在所有 AJAX 调用之前禁用按钮,然后在最外层 AJAX 中的 .always 中启用按钮。但问题是我认为启用按钮的代码发生在最里面 AJAX 的 .done 内的代码之前。是因为最外层 AJAX 中的 .always 与最内层 AJAX 中的 .done 并行运行吗?并且其中一个先于另一个完成?
解决这个问题的方法是什么?我是否需要使用 Promise 以便在所有 AJAX 调用完成后启用按钮?如果是这样,你能告诉我怎么做吗?它看起来很先进,但我不明白我一直在阅读的代码。
function loginAndEnter() {
$("#login-and-enter-btn").prop('disabled', true);
$("#login-and-enter-btn").text('請稍等...');
$.ajax({ //Outermost AJAX
type:"GET",
url:"/qrcode/login/",
data:{
"cellphone":document.getElementById("cellphone").value,
"password":document.getElementById("password").value
}
})
.done(function(responsedata) {
var parsedJson = $.parseJSON(responsedata);
if(parsedJson.result==1){
document.getElementById("token").value = parsedJson.token;
$.ajax({
type:"GET",
url:"/qrcode/entry/",
data:{
"token":document.getElementById("token").value,
"parking_lot_id":{{ $parking_lot_id }},
"in_or_out":{{ $in_or_out }}
}
})
.done(function(responsedata) {
var parsedJson = $.parseJSON(responsedata);
if(parsedJson.result==1){
$.ajax({
type:"GET",
url:"/qrcode/zero/",
data:{
"booking_id":parsedJson.Booking_ID[0].id,
"token":document.getElementById("token").value
}
})
.done(function(responsedata) { //Innermost done
var parsedJson = $.parseJSON(responsedata);
if(parsedJson.result==1){
alert("進場成功! 請使用易停網APP繳費與出場.");
window.location.href = "/download";
}
else{
alert(parsedJson.title+"\n"+parsedJson.description);
}
})
.fail(function(xhr, status, errorThrown) {
...
});
}
else{
alert(parsedJson.title+"\n"+parsedJson.description);
}
})
.fail(function(xhr, status, errorThrown) {
...
});
}
else{
alert(parsedJson.title+"\n"+parsedJson.description);
}
})
.fail(function(xhr, status, errorThrown) {
...
})
.always(function() { //Outermost always
$("#login-and-enter-btn").prop('disabled', false);
$("#login-and-enter-btn").text('登入和升起柵欄進場');
});
}
最佳答案
.always 函数不会等待其他 AJAX 请求完成,因为它是在最外层请求获得响应后立即调用的。请求是嵌套的,这意味着后续的 AJAX 请求将在其他请求解决后被调用,但如果您只想在所有请求都解决后执行某些操作,则需要 Promise。
我修改了您的代码,以展示使用 Promises 和 async/await 函数实现目标的一种方法。
function firstAJAX() {
return new Promise((resolve, reject) => {
$.ajax({ //Outermost AJAX
type:"GET",
url:"/qrcode/login/",
data:{
"cellphone": 111111111111,
"password": "pwd"
}
})
.done(function(responsedata) {
// var parsedJson = $.parseJSON(responsedata);
var parsedJson = {};
parsedJson.result = 1;
if(parsedJson.result==1){
resolve(responsedata);
}
else{
alert(parsedJson.title+"\n"+parsedJson.description);
}
})
.fail(function(xhr, status, errorThrown) {
console.log(status);
});
});
}
function secondAJAX(data) {
return new Promise((resolve, reject) => {
$.ajax({
type:"GET",
url:"/qrcode/entry/",
data:{
"token": "token",
"parking_lot_id": 11,
"in_or_out": 22
}
})
.done(function(responsedata) {
// var parsedJson = $.parseJSON(responsedata);
var parsedJson = {};
parsedJson.result = 1;
if(parsedJson.result==1){
resolve(responsedata);
}
else{
alert(parsedJson.title+"\n"+parsedJson.description);
}
})
.fail(function(xhr, status, errorThrown) {
console.log(status);
});
});
}
function thirdAJAX(data) {
return new Promise((resolve, reject) => {
$.ajax({
type:"GET",
url:"/qrcode/zero/",
data:{
"booking_id": 222,
"token":"token"
}
})
.done(function(responsedata) { //Innermost done
// var parsedJson = $.parseJSON(responsedata);
var parsedJson = {};
parsedJson.result = 1;
if(parsedJson.result==1){
alert("進場成功! 請使用易停網APP繳費與出場.");
// window.location.href = "/download";
resolve(responsedata);
}
else{
alert(parsedJson.title+"\n"+parsedJson.description);
}
})
.fail(function(xhr, status, errorThrown) {
console.log(status);
});
});
}
async function loginAndEnter() {
const first = await firstAJAX();
const second = await secondAJAX(first);
const third = await thirdAJAX(second);
$("#login-and-enter-btn").prop('disabled', false);
$("#login-and-enter-btn").text('登入和升起柵欄進場');
}
所以它的工作方式是loginAndEnter函数将等待firstAJAX、secondAJAX和thirdAJAX被解析。所有这些函数都会返回 Promise,当 GET 请求成功收到响应时,这些 Promise 就会被解析。 SecondAJAX 和 ThirdAJAX 接受一个参数,该参数是从之前调用的函数异步传递的响应(感谢“await”)。
出于我自己的测试目的,我更改了许多值,因此请在尝试之前将它们更改回您的值。
关于javascript - 第一个 AJAX 总是在最后一个嵌套 AJAX 完成之前发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55862920/