使用 jQuery deferred 中止 AJAX 请求链

Posted

技术标签:

【中文标题】使用 jQuery deferred 中止 AJAX 请求链【英文标题】:Abort chain of AJAX requests with jQuery deferred 【发布时间】:2018-06-22 02:50:43 【问题描述】:

我正在进行一系列 AJAX 调用,如下例所示,我在 http://www.dotnetcurry.com/jquery/1022/jquery-ajax-deferred-promises 找到了它。

如果 function A 中 AJAX 调用的响应是空 JSON 对象数组(即“[ ]”)?理想情况下,我不仅要中止 AJAX 调用链,还要通知用户没有找到结果。

谢谢!

function A() 
    writeMessage("Calling Function A");
    return $.ajax(
        url: "/scripts/S9/1.json",
        type: "GET",                    
        dataType: "json"
    );



function B(resultFromA) 
    writeMessage("In Function B. Result From A = " + resultFromA.data);
    return $.ajax(
        url: "/scripts/S9/2.json",
        type: "GET",
        dataType: "json"
    );



function C(resultFromB) 
    writeMessage("In Function C. Result From B =  " + resultFromB.data);
    return $.ajax(
        url: "/scripts/S9/3.json",
        type: "GET",
        dataType: "json"
    );


function D(resultFromC) 
    writeMessage("In Function D. Result From C = " + resultFromC.data);


A().then(B).then(C).then(D);

function writeMessage(msg) 
    $("#para").append(msg + "<br>");                 

【问题讨论】:

【参考方案1】:

通常,您可以让每个工作函数 A、B、C、D 返回一个对象,该对象包含响应数据以及您是否要继续调用链中的下一个函数,无论它可能是什么。像这样的:

function A(input) 
    return $.get("/scripts/S9/1.json").then(function (response) 
        return 
            continue: response.data && response.data.length,
            data: response
        ;
    );

现在您可以通过减少一组工作函数来创建一个承诺链,并在每个步骤中决定您是否要继续(在这种情况下您执行下一个工作程序)或不(您只需继续返回最后一个有效的链的其余部分的结果)。由于没有更好的名称,我已将此逻辑包装到函数 breakableChain 中。

function maybe()  return Math.random() > 0.25; 
function A(input)  console.log('in A:', input.data); return continue: maybe(), data: 'result from A';  
function B(input)  console.log('in B:', input.data); return continue: maybe(), data: 'result from B';  
function C(input)  console.log('in C:', input.data); return continue: maybe(), data: 'result from C';  
function D(input)  console.log('in D:', input.data); return continue: maybe(), data: 'result from D';  

function breakableChain(workers, init) 
    return workers.reduce(function (current, next) 
        return current.then(function (result) 
            return result.continue ? next(result) : result;
        );
    , $.Deferred().resolve(continue: true, data: init));


breakableChain([A, B, C, D], 'initial data').then(function (result) 
    console.log('overall:', result.data);
);
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

当然,您可以制作一个不需要continue 标志的非通用版本,而是将关于每个结果的假设直接硬编码到.reduce() 内的if 语句中。那会更短,但不能重复使用。

整个continue: true, data: result 只是一个约定。您的约定也可以是“如果先前的调用返回任何内容,则继续,否则停止”,方法相同,但无法返回整体结果。

【讨论】:

感谢@Tomalak 花时间写出如此详细的答案!不幸的是,第二块中的许多概念对我来说并不熟悉。我不明白该代码,所以我不知道如何应用它。我需要第二个代码块吗? 顺便问一下,你知道一个很好的资源来学习你在第二个代码块中使用的东西吗? 当然您需要第二个代码块,它可以完成所有工作。这是我的答案的核心。我理解如果你不能完全理解它,它需要对异步代码如何工作,特别是 Promises 如何工作有扎实的了解。我怀疑您也不太了解自己的代码示例。这对我来说很难解决。 我建议您阅读有关 Promises 的内容。从字面上看,几乎无限的博客文章、教程、文档(如 MDN)、关于它们是什么以及它们如何工作的各个方面的详细 Stack Overflow 答案。有了这些,你就会对什么是异步代码有所了解。如果这些概念对您来说是新的,那肯定需要一点时间,但是没有办法做到这一点。一旦您对自己的代码示例有了更好的理解,就可以集中精力对其进行渐进式更改。我的代码不是解决您问题的唯一方法,但希望随着时间的推移它会变得更加清晰。 再次感谢@Tomalak。我实际上确实理解我提到的代码示例。我从不使用我不理解的代码。我会阅读承诺,并希望最终能理解你的答案:D 我很感激你的回答。

以上是关于使用 jQuery deferred 中止 AJAX 请求链的主要内容,如果未能解决你的问题,请参考以下文章

存在中止调用时触发 jQuery 的 ajaxStop 事件

jQuery中的deferred对象的使用

jQuery.Deferred对象

jquery的deferred使用详解

jquery的deferred使用详解

jQuery: Deferred