在编写多个ajax请求时,我一直在阅读jquery中的Promises并避免"回调地狱"。
我觉得即使在阅读了所有这些内容之后,就链接请求而言,在.done(),.then()和.when()方面没有给出使用什么的简单答案。
我试图构建最基本的例子来说明我的观点。下面的代码完全按照我的意愿工作,但唯一依赖的是.done(),我无法看到其他方法(例如.then()或.when())适合这个。
所以我创建了3个PHP脚本,并使用PHP的sleep方法人为地延迟了这些脚本完成的时间。延迟时间如下:
r1.php - 5秒
r2.php - 1秒
r3.php - 3秒
脚本本身就像这样简单:
// r1.php
echo"starting r1.php
";
sleep(5); // Delay execution. Varies as described above for each script
echo"ending r1.php
";
?>
因此,如果它们并行运行,那么它们完成的顺序将是r2.php,r3.php,然后是r1.php。
但是如果我们想按顺序运行它们(r1 .php,r2.php,r3.php)并让jquery等到每个ajax请求进行到下一个之后呢?例如,如果r2.php中的某些内容取决于r1.php的结果等。
我写了以下内容 - 这正是如此:
$(document).ready(function() {
$.ajax({
url: 'ajax/r1.php',
method: 'get'
}).done(function(response1) {
console.log('After r1.php
');
console.log(response1);
$.ajax({
url: 'ajax/r2.php',
method: 'get'
}).done(function(response2) {
console.log('After r2.php
');
console.log('response1:' + response1);
console.log(response2);
$.ajax({
url: 'ajax/r3.php',
method: 'get'
}).done(function(response3) {
console.log('After r3.php
');
console.log('response1:' + response1);
console.log('response2:' + response2);
console.log(response3);
});
});
});
});
如您所见,请求按顺序完成,并占用每个PHP脚本中指定的时间:
此外,由于回调运行的范围,我可以访问处理r3.php的回调中的response1(r1.php的输出):
我的问题是:在什么情况下除.done()之外的任何函数(例如.then()或.when() - 在无数资源中提到的)实际上需要做这种类型的事情?什么时候你甚至需要.then()或.when()这种情况?
据我所知,.done()与Promise兼容。我甚至在上面的代码中用.then()替换了.done(),结果完全相同。
我已经阅读了以下所有内容,但我觉得所有这些都使问题复杂化,如何使用jquery按顺序运行ajax请求:
jQuery延迟和承诺 - .then()vs .done()
如何使用jQuery promises链接三个异步调用?
https://medium.com/coding-design/writing-better-ajax-8ee4a7fb95f
有人可以用初学者可以理解的方式解释这个吗?我正在使用jquery 3.2.1所以想要一个特定于jquery的响应,而不是vanilla JavaScript。
我最初问过这个问题,但我觉得它措辞不好而且没有包含足够的代码。所以我嘲笑了这里给出的代码来说明确切的问题。
.done()方法仅在Promise解析时调用(与.fail()相反,后者在Promise被拒绝时调用)。
.then()方法接受已解析和拒绝的回调,相当于同时使用done / fail,这样:
$.ajax().then(resolvedCallback(), rejectedCallback());
相当于
$.ajax().done(sucess()).fail(failure());
不同之处在于,多个.then()可以更容易地链接在一起,以实现更复杂的Promise解析。
.when()方法允许您将一些逻辑封装在Promise / Deffered / Thenable中,以便可以使用.then(),.done()和.fail()。如果你想要执行一些复杂或长时间运行的逻辑并且需要将它包装在Promise / Deferred中,这很有用。它还使阅读更容易:
$.when(function(){/*I do something that takes a while*/})
.then(function(){/*I succeed*/},
function(){/*I fail*/})
.then( ... )
.then( ... )
...
然后,您可以在.always()中结束链以清除任何类型的结果或执行必须始终在链的末尾发生的某些操作,无论您的承诺是否已解决或被拒绝。
编辑:全部放在一起
使用.when(),我们可以让代码等待单元完成许多工作,然后继续:
function fetchMe(url) {
return $.ajax({
url: url,
method: 'get'
});
}
$.when(fetchMe('ajax/r1.php'), fetchMe('ajax/r2.php'), fetchMe('ajax/r3.php'))
.then(function(r1, r2, r3) { // Resolve
console.log('response1: ' + r1.data);
console.log('response2: ' + r2.data);
console.log('response3: ' + r3.data);
}, function(){ // Reject!
console.log('Something broke!');
});
在此示例中,fetchMe()从$.ajax()调用返回Promise。使用.when(),我们告诉脚本在继续执行.then()之前等待所有这三个完成。 resolve方法的输入按照它们在.when()中的顺序获取延迟项,从那里,我们可以从请求中检索数据。
谢谢 - 这是一个很好的答案。在参考我的代码和我正在运行的3个脚本时,您是否可以扩展答案以显示如何将.when()和.then()合并到其中,并说明这样做的任何优点?
@Andy编辑是否回答了你的问题?
是非常的。这是一个很好的解释,我希望任何阅读jquery中的同时ajax请求的人都能读到这个。我发现的所有其他资源并没有以大多数人理解的方式解释这一点。谢谢。
console.log('*response1: ' + r1.data);语句给出*response1: undefined。如果我删除.data - 例如 - console.log('*response1: ' + r1);,它会给出输出,但最后会输出,success,[object Object]。那么输出看起来有点不同?
@Andy应该使用参数data, textStatus, jqXHR处理类似于.done()的回调。如果您没有返回任何实际数据,则data将undefined。否则你可以看看r1.jqXHR.responseText
在你的最后一段中,你写了2次.with()而不是我假设的.when() ...这是故意的吗?我很想编辑,但因为它有两次......我在犹豫。 ;)+1,无论如何,这个很好的答案。
@LouysPatriceBessette哦废话!我完全错过了!!编辑纠正错误。谢谢你的救命! :)
您可以尝试$.Deffered链接多个ajax调用以使它们顺序。
文档:HTTPS://api.jquery.com/category/deferred-object/
类似的问题:如何使所有AJAX调用顺序?
这完全没有回答这个问题。您甚至没有引用.done(),.when()或.then()。这些答案已经使这个问题变得比它需要的更复杂,特别是对于初学者。
我给你一个顺序ajax调用的解决方案。我并没有使问题复杂化。我给了你另一种方法来达到预期的效果。我会尝试以简单的方式解释它。