如何取消网络请求呢?在前端通常使用网络HTTP请求API有:XMLHttpRequestFetch,常用的请求库"jQuery","Axios"

jQuery.ajax,XMLHttpRequest都是基于XMLHttpRequest的网络请求库.
我们来看一下,如何取消正在进行中的网络请求.

有一个http://127.0.0.1:9501/api/get接口,延迟1秒钟返回结果.

XMLHttpRequest

通过abort()方法取消请求,status状态码被设置为0

const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:9501/api/get', true);
xhr.send();
xhr.abort();

请求被取消

参考:
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/abort

监听取消事件:

xhr.addEventListener('abort', (e)=>{
  console.log(e.target.status);// 0
});

jQuery Ajax 如何取消呢?

jQuery.ajax是基于xmlHttpRequest的.
参考:https://api.jquery.com/jQuery.Ajax/#jqXHR

通过jqXHR取消

    var $ajax=$.ajax({
        method:"get",
        url:'http://127.0.0.1:9501/get.php',
        success:(res)=>{console.log(res)},
        error:(e)=>{console.log(e.status,e.statusText)},
    })

    $ajax.abort();

2023-07-24T05:53:20.png

通过原生XHR取消

通过 $.ajaxSettings.xhr() 获取原生xhr.也可以直接new XMLHttpRequest
取消请求,可以用jquery的abort()也可以用原生的abort()

    var xhr=$.ajaxSettings.xhr();
    // var xhr=new XMLHttpRequest();
    var $ajax=$.ajax({
        method:"get",
        url:'http://127.0.0.1:9501/get.php',
        success:(res)=>{console.log(res)},
        error:(e)=>{console.log(e)},
        xhr:()=>xhr,
    })
    xhr.addEventListener('abort', (e)=>{
        console.log(e.target)
    });
    // $ajax.abort();
    xhr.abort();

原生abort与jQuery的abort的有什区别呢?
$ajax.abort可以自定义错误类型,error可以监听到错误回调.
原生xhr只能获取一个error类型.

$ajax.abort("手动取消了")

通过AbortController取消ajax请求.

jquery不支持signal参数,但我们可以通过beforeSend来绑定事件.

const controller = new AbortController();
const signal = controller.signal;

$.ajax({
    method:"get",
    url:'http://127.0.0.1:9501/get.php',
    success:(res)=>{console.log(res)},
    error:(e)=>{console.log(e)},
    beforeSend:(jqXhr,ajaxSettings)=>{
        signal.addEventListener("abort",function(){
            jqXhr.abort("AbortController 来取消");
        })
    }
})

controller.abort();

效果也一样的.

Fetch取消请求

Fetch 也是通过 AbortController api 来取消请求的.
参考:https://developer.mozilla.org/zh-CN/docs/Web/API/AbortController

controller = new AbortController();
const signal = controller.signal;
fetch('http://127.0.0.1:9501/get.php', { signal })
.then((response) => {
    console.log('成功', response);
})
.catch((err) => {
    console.error('失败',err);
});
controller.abort();

事件监听:

signal.addEventListener('abort', () => {
    console.log('请求被取消了');
});

或者

signal.onabort = () => {
  console.log('请求被取消了');
};

Axios 取消请求

AbortController方式取消

从v0.22.0版本之后,支持AbortController方式取消
参考: https://axios-http.com/zh/docs/cancellation

const controller = new AbortController();
axios.get('http://127.0.0.1:9501/get.php', {
   signal: controller.signal
}).then((response)=> {
    console.log("ok",response)
}).catch((err)=>{
    console.error("err",err);
});
controller.abort()

CancelToken 方式取消 (deprecated)

此 API 从 v0.22.0 开始已被弃用.

API与AbortController 使用相

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('http://127.0.0.1:9501/get.php', {
    cancelToken: source.token
}).then((response)=> {
    console.log("ok",response)
}).catch((err)=>{
    console.error("err",err);
});

source.cancel("取消");

总结

需要取消网络请求的场景:

  1. 耗时太长的请求,我们需要提前那取消
  2. 无用的网络请求或错误造成的网络请求,避免占用太多资源,取消那掉.
  3. 路由跳转时,页面上还残留很多请求时.
  4. 逻辑关系的请求,比如订单详情要获取很多补充信息,但是那业务已经不需要这个订单,其他辅助请求就没必要继续.

批量请求:
controller.signal可以共用,多个请求用一个信号时,可以同时取消.

windows.stop() 可以取消掉页面上的所有请求,包括像图片资源等.

原作者:阿金
本文地址:https://hi-arkin.com/archives/resquest-abort.html

标签: javascript Fetch Axios jQuery XMLHttpRequest ajax AbortController

(本篇完)

评论