React - 实现fetch取消、中止请求

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React - 实现fetch取消、中止请求相关的知识,希望对你有一定的参考价值。

参考技术A

项目开发过程中有时会遇到这种情况:两次查询请求相隔时间很短时,由于 接口异步 ,第一次请求可能会覆盖第二次请求返回数据,所以需要在第二次请求前先将第一次请求中止,话不多说,实现如下:
关于axios取消请求网上有很多,可自信百度,本文主要针对于fetch请求,由于fetch并没有 "取消请求" 方法,目前通过AbortController()实现

项目:Ant.Design Pro + umijs + dva

新建一个abortDispath.js文件

新建一个扩展Component

demo.js

request.js 文件中需要将signal放在options中,例如

如何取消/中止 jQuery AJAX 请求?

【中文标题】如何取消/中止 jQuery AJAX 请求?【英文标题】:How to cancel/abort jQuery AJAX request? 【发布时间】:2011-05-31 20:56:40 【问题描述】:

我有一个 AJAX 请求,每 5 秒发出一次。但问题出在 AJAX 请求之前,如果前一个请求未完成,我必须中止该请求并发出新请求。

我的代码是这样的,如何解决这个问题?

$(document).ready(
    var fn = function()
        $.ajax(
            url: 'ajax/progress.ftl',
            success: function(data) 
                //do something
            
        );
    ;

    var interval = setInterval(fn, 500);
);

【问题讨论】:

Kill ajax requests using javascript using jquery. 的可能重复项 您的问题表明请求应该每 5 秒发生一次,但代码使用 500 ms = 0.5 s。 【参考方案1】:

jquery ajax 方法返回一个XMLHttpRequest 对象。您可以使用该对象取消请求。

XMLHttpRequest 有一个abort 方法,它取消请求,但是如果请求已经发送到服务器,那么服务器将处理该请求,即使我们中止了请求但是客户端不会等待/处理响应。

xhr 对象还包含一个readyState,其中包含请求的状态(UNSENT-0、OPENED-1、HEADERS_RECEIVED-2、LOADING-3 和 DONE-4)。我们可以使用它来检查之前的请求是否完成。

$(document).ready(
    var xhr;
    
    var fn = function()
        if(xhr && xhr.readyState != 4)
            xhr.abort();
        
        xhr = $.ajax(
            url: 'ajax/progress.ftl',
            success: function(data) 
                //do something
            
        );
    ;

    var interval = setInterval(fn, 500);
);

【讨论】:

@romkyns 区别在于上面的属性readystate和下面的readyState,字符s在jQuery 1.5中大写 我想知道如果 readyState 是“LOADING-3”并且我们中止会发生什么?数据被发送到服务器,它是否被处理。我们不会知道... :S 顺便说一句,我认为 readyState 检查是不必要的,因为它被推迟了,一旦解决或拒绝它就不会运行其他检查。所以if (xhr) xhr.abort(); 也可以正常工作。 W3 在其文档中从未使用过未大写的readystate。它总是大写 readyState 并且 jquery(在 1.5 之前或之后)正确匹配 w3 规范。 @ArunPJohny,请问这个问题***.com/questions/49801146/…【参考方案2】:

为什么要中止请求?

如果每个请求花费的时间超过五秒,会发生什么?

如果随请求传递的参数未更改,则不应中止请求。 例如:- 请求用于检索通知数据。 在这种情况下,最好的方法是仅在完成之前的 Ajax 请求后才设置新请求。

$(document).ready(

    var fn = function()

        $.ajax(
            url: 'ajax/progress.ftl',
            success: function(data) 
                //do something
            ,

            complete: function()setTimeout(fn, 500);
        );
    ;

     var interval = setTimeout(fn, 500);

);

【讨论】:

这是个坏主意。开始新呼叫时,您不希望触发上一个呼叫的完整事件。使用这种方法可能会得到非常奇怪的结果。【参考方案3】:

当您向服务器发出请求时,首先让它检查进度是否不为空(或获取该数据)。如果它正在获取数据,则中止先前的请求并启动新的请求。

var progress = null

function fn ()     
    if (progress) 
        progress.abort();
    
    progress = $.ajax('ajax/progress.ftl', 
        success: function(data) 
            //do something
            progress = null;
        
    );

【讨论】:

【参考方案4】:

jQuery: 以此为起点——作为灵感。 我是这样解决的: (这不是一个完美的解决方案,它只是中止了最后一个实例并且是 WIP 代码)

var singleAjax = function singleAjax_constructor(url, params) 
    // remember last jQuery's get request
    if (this.lastInstance) 
        this.lastInstance.abort();  // triggers .always() and .fail()
        this.lastInstance = false;
    

    // how to use Deferred : http://api.jquery.com/category/deferred-object/
    var $def = new $.Deferred();

    // pass the deferrer's request handlers into the get response handlers
    this.lastInstance = $.get(url, params)
        .fail($def.reject)         // triggers .always() and .fail()
        .success($def.resolve);    // triggers .always() and .done()

    // return the deferrer's "control object", the promise object
    return $def.promise();



// initiate first call
singleAjax('/ajax.php', a: 1, b: 2)
    .always(function(a,b,c) console && console.log(a,b,c););

// second call kills first one
singleAjax('/ajax.php', a: 1, b: 2)
    .always(function(a,b,c) console && console.log(a,b,c););
    // here you might use .always() .fail() .success() etc.

【讨论】:

【参考方案5】:

您还应该检查 readyState 0。因为当您使用 xhr.abort() 时,此函数在此对象中将 readyState 设置为 0,并且您的 if 检查将始终为 true - readyState !=4

$(document).ready(
    var xhr;

    var fn = function()
        if(xhr && xhr.readyState != 4 && xhr.readyState != 0)
            xhr.abort();
        
        xhr = $.ajax(
            url: 'ajax/progress.ftl',
            success: function(data) 
                //do something
            
        );
    ;

    var interval = setInterval(fn, 500);
); 

【讨论】:

您是否复制并粘贴了 Arun 的答案?因为像这样的两个代码块完全一样的可能性,间距和所有... @user2700923 他的帖子不完全一样。他的观点是我们还应该检查 readyState 0。但是,这更适合作为对 Arun 答案的评论。【参考方案6】:

我知道这可能有点晚了,但我遇到了类似的问题,调用 abort 方法并没有真正中止请求。相反,浏览器仍在等待它从未使用过的响应。 这段代码解决了这个问题。

 try 
        xhr.onreadystatechange = null;
        xhr.abort();
 catch (e) 

【讨论】:

【参考方案7】:

您可以使用 jquery-validate.js 。以下是 jquery-validate.js 中的代码 sn-p。

// ajax mode: abort
// usage: $.ajax( mode: "abort"[, port: "uniqueport"]);
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()

var pendingRequests = ,
    ajax;
// Use a prefilter if available (1.5+)
if ( $.ajaxPrefilter ) 
    $.ajaxPrefilter(function( settings, _, xhr ) 
        var port = settings.port;
        if ( settings.mode === "abort" ) 
            if ( pendingRequests[port] ) 
                pendingRequests[port].abort();
            
            pendingRequests[port] = xhr;
        
    );
 else 
    // Proxy ajax
    ajax = $.ajax;
    $.ajax = function( settings ) 
        var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
            port = ( "port" in settings ? settings : $.ajaxSettings ).port;
        if ( mode === "abort" ) 
            if ( pendingRequests[port] ) 
                pendingRequests[port].abort();
            
            pendingRequests[port] = ajax.apply(this, arguments);
            return pendingRequests[port];
        
        return ajax.apply(this, arguments);
    ;

这样你只需要在发出ajax请求时将参数mode设置为abort

参考:https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.js

【讨论】:

【参考方案8】:

创建一个函数来调用您的 API。在这个函数中,我们定义了请求callApiRequest = $.get(...——尽管这是一个变量的定义,请求被立即调用,但是现在我们将请求定义为一个变量。在调用请求之前,我们检查我们的变量是否已定义 typeof(callApiRequest) != 'undefined' 以及它是否正在等待 suggestCategoryRequest.state() == 'pending' - 如果两者都是 true,我们将 .abort() 请求将阻止成功回调运行。

// We need to wrap the call in a function
callApi = function () 

    //check if request is defined, and status pending
    if (typeof(callApiRequest) != 'undefined'
        && suggestCategoryRequest.state() == 'pending') 

        //abort request
        callApiRequest.abort()

    

    //define and make request
    callApiRequest = $.get("https://example.com", function (data) 

        data = JSON.parse(data); //optional (for JSON data format)
        //success callback

    );

您的服务器/API 可能不支持中止请求(如果 API 已经执行了一些代码怎么办?),但不会触发 javascript 回调。这很有用,例如,当您向用户提供输入建议时,例如主题标签输入。

您可以通过添加错误回调的定义来进一步扩展此功能 - 如果请求被中止会发生什么。

此 sn-p 的常见用例是在 keypress 事件上触发的文本输入。您可以使用超时来防止发送(某些)请求,您必须取消 .abort()

【讨论】:

以上是关于React - 实现fetch取消、中止请求的主要内容,如果未能解决你的问题,请参考以下文章

使用 redux-thunk 取消之前的 fetch 请求

使用 Expo 取消 React Native 中的异步获取请求

请求被中止:请求被取消。没有解决方案有效

如何取消/中止 jQuery AJAX 请求?

中止/取消/放弃angular js中的http请求并重试

System.Net.WebException:请求被中止:请求被取消