# 请求中断
# 写这篇文章初衷
- web开发中前后端联调贯穿整个开发
- http请求可能会产生重复请求
- 学习使用方法
- 有些第三方库升级后,具体使用方法需要看官方文档
# 原生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
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
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
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
2
3
4
5
6
7
- 然后,在你的 fetch 请求中使用这个对象的 signal 属性。
fetch(url, { signal: controller.signal });
1
- 在你需要取消请求时,调用 controller.abort() 方法。
controller.abort();
1
2
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
2
3
4
5
6
7
8
调用 controller.abort() 方法可以立即取消请求,但是在某些情况下可能不会立即生效。
首先,请确保你在请求中使用了 AbortController 的 signal 属性,例如在 fetch 请求中:
fetch(url, { signal: controller.signal });
1
2
2
然后,在取消请求时,可以尝试以下方法来确保取消立即生效:
立即调用 controller.abort() 。在请求还未发出或者正在进行时立即取消。
在 fetch promise 的 then 块或者 catch 块中调用 controller.abort() 方法。这样就可以确保请求已经发出,并且正在进行,可以立即取消。
使用 setTimeout 函数调用 controller.abort() 方法。 例如:
setTimeout(() => {
controller.abort();
}, 0);
1
2
3
4
2
3
4
这样可以确保请求已经发出,并且正在进行,可以立即取消。
注意:在取消操作后,在 fetch promise 上的 catch 块将被调用,并且将传递一个 AbortError 对象。
总之,在使用AbortController取消fetch请求时,需要根据不同的场景来确定最佳的取消时机。
1
2
2
← 内存泄漏