如何按连续顺序执行多个链接的 $.post() 调用?
How to execute multiple, chained $.post() calls in consecutive order?
我正在努力实现的目标
我需要触发1到3个不同的$.post()
请求,是1次调用、2次连续调用还是3次连续调用由一些基本用户selection决定。每个调用只能在上一个调用完全结束后才开始。
我正在处理 3 个简单的行为案例——用户在看到 "Checkbox 1," "Checkbox 2," 和一个 "Continue" 按钮时,选择
- Select 什么都没有,然后按 "Continue" 按钮,这会调用 '/remote.php',
- 用户选择仅 select "Checkbox 1" 或 "Checkbox 2," 然后按下 "Continue" 按钮,调用
$.post() Function 1
绑定到复选框 1,或 $.post() Function 2
绑定到复选框 2,然后对 '/remote.php', 进行 XHR 调用
- 或者用户 select 都选中复选框 1 + 2,然后按继续,调用
$.post() Function 1
,然后调用 $.post() Function 2
,然后对 '/remote.php'.
我需要确保继续按钮 $.post()
函数不会触发,直到复选框绑定 $.post()
函数触发并完成。
问题
问题是,如果 Checkbox 1 selected 和 Checkbox 2 selected,然后按下 Continue 按钮,据我了解,加载顺序应该是:
- 复选框 1 绑定
$.post()
请求触发并完成,然后
- 复选框 2 绑定
$.post()
请求触发并完成,然后
- 继续按钮绑定
$.post()
触发,并在绑定到 "Continue" 按钮绑定函数的函数末尾通过 AJAX 更改页面。
所以,结果应该是这样的:
XHR finished loading: POST "/cart.php?action=add&product_id=1280".
XHR finished loading: POST "/cart.php?action=add&product_id=1284".
XHR finished loading: POST "/remote.php".
反而经常这样出来:
XHR finished loading: POST "/cart.php?action=add&product_id=1280".
XHR finished loading: POST "/remote.php".
XHR finished loading: POST "/cart.php?action=add&product_id=1284".
因此,当页面因 "last"/" 继续按钮功能末尾的 AJAX 而发生变化时,复选框 1 或复选框 2 操作均未发生,或者两者之一或两者之一确实在后端注册(即添加到购物车),但没有反映在 AJAXified DOM 中,因为它们应该作为最终的 AJAX 触发并在之前完成之前的 $.post() 调用已经完成。
我的代码
HTML
HTML基础:
<form method="post" action="#" onsubmit="newChooseShippingProvider(); return false;">
<label for="delSigCheck" class="del-sig-text"><input id="delSigCheck" type="checkbox" onchange="addDelSigToCart();" title="Add Delivery Signature"></label>
<label for="addInsCheck" class="ins-add-calc"><input id="addInsCheck" type="checkbox" onchange="addInsToCart();" title="Add Delivery Signature" data-ins-id="1284"></label>
<input type="submit" value="Continue" class="btn Small">
</form>
Javascript/jQuery
这是我最近的--第四次或第五次--尝试,但仍然无效:
function addDelSigToCart() {
$('#delSigCheck').toggleClass('checked');
}
function addInsToCart() {
$('#addInsCheck').toggleClass('checked');
}
function newChooseShippingProvider() {
var originalCheckout = ExpressCheckout.ChooseShippingProvider();
if ($('.ShippingProviderList .radio span').hasClass('checked')) {
var addInsCheck = $('#addInsCheck').hasClass('checked');
var delSigCheck = $('#delSigCheck').hasClass('checked');
var insId = $('#addInsCheck').attr('data-ins-id');
var addDelSigUrl = '/cart.php?action=add&product_id=1280';
var addInsUrl = '/cart.php?action=add&product_id=' + insId;
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl, function() {
$.post(addInsUrl, function() {
originalCheckout;
});
});
} else if (!delSigCheck && !addInsCheck) {
originalCheckout;
} else if (delSigCheck && !addInsCheck) {
$.post(addDelSigUrl, function() {
originalCheckout;
});
} else if (!delSigCheck && addInsCheck) {
$.post(addInsUrl, function() {
originalCheckout;
});
}
} else {
originalCheckout;
}
我试过的
我已经经历了几个链接 $.post()
调用的版本,但似乎没有什么能始终如一地工作。
我现在使用的以及经过大量测试似乎对我最有效的方法是使用 setTimeout
来延迟链接函数,如下所示:
...
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl);
setTimeout(function() {
$.post(addInsUrl);
setTimeout(function() {
ExpressCheckout.ChooseShippingProvider();
}, 1300);
}, 1300);
} else if ...
上面的这个版本是我现在使用的,因为它似乎给出了最一致的结果,看到脚本加载通常为 1,2,3,然后是 DOM AJAX 根据功能 1 和 2 进行适当更改。但是,我认为 setTimeout 无法正常工作,因为即使我将其增加到 5000 或 10000,也会执行操作 "instantaneously" 并且不会发生延迟(至少肯定不会接近 5-10 秒)。
我也试过将函数放在 $.post()
的成功回调中:
...
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl, function() {
setTimeout(function() {
$.post(addInsUrl, function() {
setTimeout(function() {
originalCheckout;
}, 1300);
});
}, 1300);
});
} else if ...
最后我也试过了:
$.when($.post(addDelSigUrl)).then(originalCheckout);
以及 .done
和 success:
但其中 none 有效,并且 $.posts() 以意外的顺序加载,失败.
问题
- 我做错了什么?
- 我怎样才能做到 1 次装满,然后 2 次装满,然后才 3 次点火和装填?
更新 1:
我刚试过 :
$.post(addDelSigUrl, { cache: false }).then(function(data1) {
//CONSOLE.LOGing HERE
console.log(data1);
return $.post(addInsUrl, { cache: false });
}).then(function(data2) {
//CONSOLE.LOGing HERE
console.log(data2);
return originalCheckout;
});
但结果仍然是:
XHR finished loading: POST "/cart.php?action=add&product_id=1280".
XHR finished loading: POST "/remote.php".
XHR finished loading: POST "/cart.php?action=add&product_id=1284".
并且两个 console.logs 在第一个 "XHR ..." 之后立即触发,然后 /remote.php 触发(尽管它应该作为 originalCheckout 的一部分最后触发),然后第三个 XHR 触发。
更新 2
现在我们通过 .then()
以正确的顺序触发和加载 XHR,我遇到的第二部分问题是 /remote.php
的第三个 XHR 更新了 DOM 通过 AJAX 使用来自后端的数据。该数据的一部分是第 1 和第 2 $.posts
。
我认为第 3 个 AJAX 调用在通过服务器端 PHP 在后端采取某些操作之前触发并完成几毫秒,因此超过 50% 的时间,通过第三次 AJAX 调用的 DOM 更新丢失了第一次 and/or 第二次调用的数据(通常 DOM 更改包括 Checkbox 1/AJAX 调用1,但不是 2)。
我该如何解决这个问题?我已经尝试过 setTimeout 但它似乎无法正常工作,即使我将它设置为 30000,第 3 个 AJAX 在第 1 个/第 2 个完成后立即触发。
最新前端代码:
function newChooseShippingProvider() {
if ($('.ShippingProviderList .radio span').hasClass('checked')) {
var addInsCheck = $('#addInsCheck').hasClass('checked');
var delSigCheck = $('#delSigCheck').hasClass('checked');
var insId = $('#addInsCheck').attr('data-ins-id');
var addDelSigUrl = '/cart.php?action=add&product_id=1280';
var addInsUrl = '/cart.php?action=add&product_id=' + insId;
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl).then(function(data1) {
return $.post(addInsUrl);
}).then(function(data2) {
return ExpressCheckout.ChooseShippingProvider();
});
} else if (!delSigCheck && !addInsCheck) {
ExpressCheckout.ChooseShippingProvider();
} else if (delSigCheck && !addInsCheck) {
$.post(addDelSigUrl).then(function(data1) {
return ExpressCheckout.ChooseShippingProvider();
});
} else if (!delSigCheck && addInsCheck) {
$.post(addInsUrl).then(function(data1) {
return ExpressCheckout.ChooseShippingProvider();
});
}
} else {
ExpressCheckout.ChooseShippingProvider();
}
}
如果您 "chain" AJAX post 操作(意味着您在收到上一次调用的数据后执行您的过程),那么不会发生任何奇怪的事情。
从症状我会想到更多与缓存相关的问题。向查询添加一个额外的随机值是一种快速而肮脏的方式,可以摆脱缓存结果和响应而不是应该缓存结果的人。此外,使用 POST 请求而不是 GET(如果可能)可能有助于解决此问题,并更好地传达操作是不应跳过或乱序执行的突变的想法。
请注意,过时的响应问题可能出现在多个级别:浏览器、代理、Web 服务器、cms 插件...
排序 jQuery ajax 操作的最简单方法是使用内置承诺:
$.post(...).then(function(data1) {
return $.post(...);
}).then(function(data2) {
return $.post(...);
}).then(function(data3) {
// everything done here
});
向您展示精确排序的工作演示:http://jsfiddle.net/jfriend00/zcfr2xy0/
好的,看来问题出在您这样做:
var originalCheckout = ExpressCheckout.ChooseShippingProvider();
然后您认为稍后您可以这样做:
originalCheckout;
这将以某种方式执行前者。事实并非如此。您的 ExpressCheckout.ChooseShippingProvider()
函数会立即执行,并且执行该函数的 return 结果将分配给 originalCheckout
。
你根本不能那样做。当函数名称后有 ()
时,这意味着立即执行它。我建议您只需将 originalCheckout;
的所有实例替换为 ExpressCheckout.ChooseShippingProvider();
.
我正在努力实现的目标
我需要触发1到3个不同的$.post()
请求,是1次调用、2次连续调用还是3次连续调用由一些基本用户selection决定。每个调用只能在上一个调用完全结束后才开始。
我正在处理 3 个简单的行为案例——用户在看到 "Checkbox 1," "Checkbox 2," 和一个 "Continue" 按钮时,选择
- Select 什么都没有,然后按 "Continue" 按钮,这会调用 '/remote.php',
- 用户选择仅 select "Checkbox 1" 或 "Checkbox 2," 然后按下 "Continue" 按钮,调用
$.post() Function 1
绑定到复选框 1,或$.post() Function 2
绑定到复选框 2,然后对 '/remote.php', 进行 XHR 调用
- 或者用户 select 都选中复选框 1 + 2,然后按继续,调用
$.post() Function 1
,然后调用$.post() Function 2
,然后对 '/remote.php'.
我需要确保继续按钮 $.post()
函数不会触发,直到复选框绑定 $.post()
函数触发并完成。
问题
问题是,如果 Checkbox 1 selected 和 Checkbox 2 selected,然后按下 Continue 按钮,据我了解,加载顺序应该是:
- 复选框 1 绑定
$.post()
请求触发并完成,然后 - 复选框 2 绑定
$.post()
请求触发并完成,然后 - 继续按钮绑定
$.post()
触发,并在绑定到 "Continue" 按钮绑定函数的函数末尾通过 AJAX 更改页面。
所以,结果应该是这样的:
XHR finished loading: POST "/cart.php?action=add&product_id=1280".
XHR finished loading: POST "/cart.php?action=add&product_id=1284".
XHR finished loading: POST "/remote.php".
反而经常这样出来:
XHR finished loading: POST "/cart.php?action=add&product_id=1280".
XHR finished loading: POST "/remote.php".
XHR finished loading: POST "/cart.php?action=add&product_id=1284".
因此,当页面因 "last"/" 继续按钮功能末尾的 AJAX 而发生变化时,复选框 1 或复选框 2 操作均未发生,或者两者之一或两者之一确实在后端注册(即添加到购物车),但没有反映在 AJAXified DOM 中,因为它们应该作为最终的 AJAX 触发并在之前完成之前的 $.post() 调用已经完成。
我的代码
HTML
HTML基础:
<form method="post" action="#" onsubmit="newChooseShippingProvider(); return false;">
<label for="delSigCheck" class="del-sig-text"><input id="delSigCheck" type="checkbox" onchange="addDelSigToCart();" title="Add Delivery Signature"></label>
<label for="addInsCheck" class="ins-add-calc"><input id="addInsCheck" type="checkbox" onchange="addInsToCart();" title="Add Delivery Signature" data-ins-id="1284"></label>
<input type="submit" value="Continue" class="btn Small">
</form>
Javascript/jQuery
这是我最近的--第四次或第五次--尝试,但仍然无效:
function addDelSigToCart() {
$('#delSigCheck').toggleClass('checked');
}
function addInsToCart() {
$('#addInsCheck').toggleClass('checked');
}
function newChooseShippingProvider() {
var originalCheckout = ExpressCheckout.ChooseShippingProvider();
if ($('.ShippingProviderList .radio span').hasClass('checked')) {
var addInsCheck = $('#addInsCheck').hasClass('checked');
var delSigCheck = $('#delSigCheck').hasClass('checked');
var insId = $('#addInsCheck').attr('data-ins-id');
var addDelSigUrl = '/cart.php?action=add&product_id=1280';
var addInsUrl = '/cart.php?action=add&product_id=' + insId;
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl, function() {
$.post(addInsUrl, function() {
originalCheckout;
});
});
} else if (!delSigCheck && !addInsCheck) {
originalCheckout;
} else if (delSigCheck && !addInsCheck) {
$.post(addDelSigUrl, function() {
originalCheckout;
});
} else if (!delSigCheck && addInsCheck) {
$.post(addInsUrl, function() {
originalCheckout;
});
}
} else {
originalCheckout;
}
我试过的
我已经经历了几个链接 $.post()
调用的版本,但似乎没有什么能始终如一地工作。
我现在使用的以及经过大量测试似乎对我最有效的方法是使用 setTimeout
来延迟链接函数,如下所示:
...
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl);
setTimeout(function() {
$.post(addInsUrl);
setTimeout(function() {
ExpressCheckout.ChooseShippingProvider();
}, 1300);
}, 1300);
} else if ...
上面的这个版本是我现在使用的,因为它似乎给出了最一致的结果,看到脚本加载通常为 1,2,3,然后是 DOM AJAX 根据功能 1 和 2 进行适当更改。但是,我认为 setTimeout 无法正常工作,因为即使我将其增加到 5000 或 10000,也会执行操作 "instantaneously" 并且不会发生延迟(至少肯定不会接近 5-10 秒)。
我也试过将函数放在 $.post()
的成功回调中:
...
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl, function() {
setTimeout(function() {
$.post(addInsUrl, function() {
setTimeout(function() {
originalCheckout;
}, 1300);
});
}, 1300);
});
} else if ...
最后我也试过了:
$.when($.post(addDelSigUrl)).then(originalCheckout);
以及 .done
和 success:
但其中 none 有效,并且 $.posts() 以意外的顺序加载,失败.
问题
- 我做错了什么?
- 我怎样才能做到 1 次装满,然后 2 次装满,然后才 3 次点火和装填?
更新 1:
我刚试过
$.post(addDelSigUrl, { cache: false }).then(function(data1) {
//CONSOLE.LOGing HERE
console.log(data1);
return $.post(addInsUrl, { cache: false });
}).then(function(data2) {
//CONSOLE.LOGing HERE
console.log(data2);
return originalCheckout;
});
但结果仍然是:
XHR finished loading: POST "/cart.php?action=add&product_id=1280".
XHR finished loading: POST "/remote.php".
XHR finished loading: POST "/cart.php?action=add&product_id=1284".
并且两个 console.logs 在第一个 "XHR ..." 之后立即触发,然后 /remote.php 触发(尽管它应该作为 originalCheckout 的一部分最后触发),然后第三个 XHR 触发。
更新 2
现在我们通过 .then()
以正确的顺序触发和加载 XHR,我遇到的第二部分问题是 /remote.php
的第三个 XHR 更新了 DOM 通过 AJAX 使用来自后端的数据。该数据的一部分是第 1 和第 2 $.posts
。
我认为第 3 个 AJAX 调用在通过服务器端 PHP 在后端采取某些操作之前触发并完成几毫秒,因此超过 50% 的时间,通过第三次 AJAX 调用的 DOM 更新丢失了第一次 and/or 第二次调用的数据(通常 DOM 更改包括 Checkbox 1/AJAX 调用1,但不是 2)。
我该如何解决这个问题?我已经尝试过 setTimeout 但它似乎无法正常工作,即使我将它设置为 30000,第 3 个 AJAX 在第 1 个/第 2 个完成后立即触发。
最新前端代码:
function newChooseShippingProvider() {
if ($('.ShippingProviderList .radio span').hasClass('checked')) {
var addInsCheck = $('#addInsCheck').hasClass('checked');
var delSigCheck = $('#delSigCheck').hasClass('checked');
var insId = $('#addInsCheck').attr('data-ins-id');
var addDelSigUrl = '/cart.php?action=add&product_id=1280';
var addInsUrl = '/cart.php?action=add&product_id=' + insId;
if (delSigCheck && addInsCheck) {
$.post(addDelSigUrl).then(function(data1) {
return $.post(addInsUrl);
}).then(function(data2) {
return ExpressCheckout.ChooseShippingProvider();
});
} else if (!delSigCheck && !addInsCheck) {
ExpressCheckout.ChooseShippingProvider();
} else if (delSigCheck && !addInsCheck) {
$.post(addDelSigUrl).then(function(data1) {
return ExpressCheckout.ChooseShippingProvider();
});
} else if (!delSigCheck && addInsCheck) {
$.post(addInsUrl).then(function(data1) {
return ExpressCheckout.ChooseShippingProvider();
});
}
} else {
ExpressCheckout.ChooseShippingProvider();
}
}
如果您 "chain" AJAX post 操作(意味着您在收到上一次调用的数据后执行您的过程),那么不会发生任何奇怪的事情。
从症状我会想到更多与缓存相关的问题。向查询添加一个额外的随机值是一种快速而肮脏的方式,可以摆脱缓存结果和响应而不是应该缓存结果的人。此外,使用 POST 请求而不是 GET(如果可能)可能有助于解决此问题,并更好地传达操作是不应跳过或乱序执行的突变的想法。
请注意,过时的响应问题可能出现在多个级别:浏览器、代理、Web 服务器、cms 插件...
排序 jQuery ajax 操作的最简单方法是使用内置承诺:
$.post(...).then(function(data1) {
return $.post(...);
}).then(function(data2) {
return $.post(...);
}).then(function(data3) {
// everything done here
});
向您展示精确排序的工作演示:http://jsfiddle.net/jfriend00/zcfr2xy0/
好的,看来问题出在您这样做:
var originalCheckout = ExpressCheckout.ChooseShippingProvider();
然后您认为稍后您可以这样做:
originalCheckout;
这将以某种方式执行前者。事实并非如此。您的 ExpressCheckout.ChooseShippingProvider()
函数会立即执行,并且执行该函数的 return 结果将分配给 originalCheckout
。
你根本不能那样做。当函数名称后有 ()
时,这意味着立即执行它。我建议您只需将 originalCheckout;
的所有实例替换为 ExpressCheckout.ChooseShippingProvider();
.