# 请求中断

# 写这篇文章初衷

  1. web开发中前后端联调贯穿整个开发
  2. http请求可能会产生重复请求
  3. 学习使用方法
  4. 有些第三方库升级后,具体使用方法需要看官方文档

# 原生XHR中断

let xhr = new XMLHttpRequest();
xhr.open("GET", "http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test?username=zs&age=20", true);
xhr.onload = function(){
    console.log(xhr.responseText)
}
xhr.send();
//在谷歌浏览器的低速3g下面测试
//通过XMLHttpRequest实例的abort方法取消请求
setTimeout(() => xhr.abort(), 100);
1
2
3
4
5
6
7
8
9

# $.ajax中断



let ajaxInstance = $.ajax({
  url,
  data,
  success,
  dataType,
  ....
});

ajaxInstance.abort();

1
2
3
4
5
6
7
8
9
10
11
12

# axios使用

//存储请求信息和取消方法的的map对象    
const pendingRequest = new Map();  
//根据请求的信息(请求方式,url,请求get/post数据),产生map的key
function getRequestKey(config){
    const { method, url, params, data } = config;
    return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}   
//请求拦截器
axios.interceptors.request.use(
    function (config) {
    //根据请求的信息(请求方式,url,请求get/post数据),产生map的key
    let requestKey = getRequestKey(config)
    //判断请求是否重复
    if(pendingRequest.has(requestKey)){
        //取消上次请求
        let cancel = pendingRequest.get(requestKey)
        cancel()
        //删除请求信息
        pendingRequest.delete(requestKey) 
    }
    //把请求信息,添加请求到map当中
    // 生成取消方法
    config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
        // 把取消方法添加到map
        if (!pendingRequest.has(requestKey)) {
            pendingRequest.set(requestKey, cancel)
        }
    })
    return config;
  },
  (error) => {
     return Promise.reject(error);
  }
);
//删除请求信息
function delPendingRequest(config){
    let requestKey = getRequestKey(config)
    if(pendingRequest.has(requestKey)){
        pendingRequest.delete(requestKey)   
    } 
}
//响应拦截器
axios.interceptors.response.use(
  (response) => {
        //请求成功
        //删除请求的信息
        delPendingRequest(response.config)
        return response;
   },
   (error) => {
        //请求失败
        //不是取消请求的错误
        if (!axios.isCancel(error)){
            //服务器报400,500报错,删除请求信息
            delPendingRequest(error.config || {})
        } 
        return Promise.reject(error);
   }
);
let sendPost = function(data){
    return axios({
        url: 'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test',
        method: 'post',
        data
    })
}
new Vue({
    el: '#app',
    mounted() {
        this.$refs.btn1.click()
        this.$refs.btn2.click()
    },
    methods: {
        // 使用lodash对请求方法做防抖
        //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果
        onClick1: async function(){
            let res = await sendPost({username:'zs', age: 20})
            console.log('请求1的结果', res.data)
        },
        onClick2: async function(){
            let res = await sendPost({username:'zs', age: 20})
            console.log('请求2的结果', res.data)
        },
    },
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

# fetch使用


> 使用 AbortController 和 fetch 可以取消重复请求。使用方式如下:

1. 首先,在你的代码中创建一个 AbortController 对象。

```js
const controller = new AbortController();
1
2
3
4
5
6
7
  1. 然后,在你的 fetch 请求中使用这个对象的 signal 属性。
fetch(url, { signal: controller.signal });
1
  1. 在你需要取消请求时,调用 controller.abort() 方法。
controller.abort();

1
2

error 注意:AbortController 是一个新的API, 浏览器支持可能不完全。 在取消操作后,在 fetch promise 上的 catch 块将被调用,并且将传递一个 AbortError 对象。

fetch(url, { signal: controller.signal }).catch(err => {
    if (err.name === 'AbortError') {
      console.log('Fetch abort')
    } else {
      console.log('Fetch Error:', err)
    }
  });
任何时候都可以调用 controller.abort() 取消fetch请求,但是请注意在某些情况下取消可能不会立即生效。
1
2
3
4
5
6
7
8

调用 controller.abort() 方法可以立即取消请求,但是在某些情况下可能不会立即生效。

首先,请确保你在请求中使用了 AbortController 的 signal 属性,例如在 fetch 请求中:

fetch(url, { signal: controller.signal });

1
2

然后,在取消请求时,可以尝试以下方法来确保取消立即生效:

立即调用 controller.abort() 。在请求还未发出或者正在进行时立即取消。

在 fetch promise 的 then 块或者 catch 块中调用 controller.abort() 方法。这样就可以确保请求已经发出,并且正在进行,可以立即取消。

使用 setTimeout 函数调用 controller.abort() 方法。 例如:

setTimeout(() => {
    controller.abort();
}, 0);

1
2
3
4

这样可以确保请求已经发出,并且正在进行,可以立即取消。

注意:在取消操作后,在 fetch promise 上的 catch 块将被调用,并且将传递一个 AbortError 对象。

总之,在使用AbortController取消fetch请求时,需要根据不同的场景来确定最佳的取消时机。



1
2
最后更新时间: 5/19/2023, 1:43:40 PM