jquery - 使用 .done()、.then() 和 .when() 以给定顺序发出 ajax 请求

Posted

技术标签:

【中文标题】jquery - 使用 .done()、.then() 和 .when() 以给定顺序发出 ajax 请求【英文标题】:jquery - usage of .done(), .then() and .when() for making ajax requests in a given order 【发布时间】:2019-01-26 17:55:24 【问题描述】:

我一直在阅读有关 jquery 中 Promises 的大量信息,并在发出多个 ajax 请求时避免“回调地狱”。

我觉得即使在阅读了所有这些内容之后,对于使用什么 - 就 .done().then().when() 而言 - 在链接请求方面,也没有给出简单的答案。

我尝试构建最基本的示例来说明我的观点。下面的代码完全按照我的意愿工作,但它唯一依赖的是.done(),我看不出其他方法(例如.then().when())适合于此。

所以我创建了 3 个 php 脚本并使用 PHP 的 sleep 方法人为地延迟了这些脚本需要多长时间才能完成。延迟设置如下:

r1.php - 5 秒 r2.php - 1 秒 r3.php - 3 秒

脚本本身就这么简单:

<?php
    // r1.php
    echo "starting r1.php \n";
    sleep(5); // Delay execution. Varies as described above for each script
    echo "ending r1.php \n";
?>

因此,如果这些并行运行,它们完成的顺序将是r2.phpr3.php,然后是r1.php

但是,如果我们想按顺序运行它们(r1.php、r2.phpr3.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\n');
       console.log(response1);

       $.ajax(
            url: 'ajax/r2.php',
            method: 'get'
       ).done(function(response2) 
           console.log('After r2.php\n');
           console.log('response1:' + response1);
           console.log(response2);

           $.ajax(
                url: 'ajax/r3.php',
                method: 'get'
           ).done(function(response3) 
               console.log('After r3.php\n');
               console.log('response1:' + response1);
               console.log('response2:' + response2);
               console.log(response3);
           );

       );
   );

);

如您所见,请求按顺序完成,并花费每个 PHP 脚本中指定的时间:

此外,由于回调运行的范围,我可以在处理 r3.php 的回调中访问,例如 response1r1.php 的输出):

我的问题是:在什么情况下,除了.done()(如.then().when()——无数资源中提到的)之外的任何功能实际上需要做这种类型的事物?对于这种情况,您什么时候甚至需要 .then().when()

据我了解,.done() 与 Promise 兼容。我什至在上面的代码中用.then() 替换了.done(),结果完全一样。

我已阅读以下所有内容,但我觉得所有这些都使问题复杂化,即如何使用 jquery 按顺序运行 ajax 请求:

jQuery deferreds and promises - .then() vs .done() How do I chain three asynchronous calls using jQuery promises? https://medium.com/coding-design/writing-better-ajax-8ee4a7fb95f

请有人能以初学者可以理解的方式解释这一点吗?我正在使用 jquery 3.2.1 所以想要一个特定于 jquery 的响应,而不是 vanilla javascript

我最初问过this question,但我觉得它的措辞很糟糕,并且没有包含足够的代码。所以我已经模拟了这里给出的代码来说明确切的问题。

【问题讨论】:

【参考方案1】:

.done() 方法仅在 Promise 解析时调用(与 .fail() 相对,后者在 Promise 被拒绝时调用)。

.then()方法接受一个resolved和一个rejected回调,相当于同时使用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】:

您可以尝试$.Deffered 链接多个 ajax 调用以使它们连续。

文档:https://api.jquery.com/category/deferred-object/ 类似问题:How to make all AJAX calls sequential?

【讨论】:

这根本不能回答问题。你甚至没有提到.done().when().then()。这些答案已经使这个问题变得比需要的复杂,尤其是对于初学者。 我给了你一个用于进行顺序 ajax 调用的解决方案。我没有使问题复杂化。我给了你另一种方法来达到预期的结果。我会尽量用简单的方式来解释。

以上是关于jquery - 使用 .done()、.then() 和 .when() 以给定顺序发出 ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章

jquery $.when() .then() 和 .done() 之间的区别

jquery deferred done then区别

jQuery的延迟对象

jQuery的延迟对象

$.when().done().then()的用法

jquery的defer