先来说一说“中断请求”的实际场景,当页面有多个tab页签时,每次切换页签都会去请求数据,频繁的切换就会去请求很多次,比如A页签切换到B页签,A页签请求完全是不必要的,这时候可以在切换时中断请求。
AbortController实验室功能,已经在主流浏览器实现,IE浏览器可以不支持,需要导入polyfill。
AbortController
接口表示一个控制器对象,允许你根据需要中止一个或多个 Web请求。官网参考:https://developer.mozilla.org...
1、axios
axios已经实现AbortController,具体实践如下:
// fontend
import React, { useEffect } from 'react';
import axios from 'axios';
const AbortController = () => {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
useEffect(() => {
axios.post('http://127.0.0.1:8088/getData', {name: 'zs', pwd: '123456'}, {cancelToken: source.token})
.then(res => {
console.log(res);
})
}, []);
const abort = () => {
source.cancel('cancle request!');
}
return (
<>
this is a abortController page.
>
)
}
export default AbortController;
// backend
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser')
const app = express();
app.use(cors({
origin: '*',
allowedHeaders: ['content-type'],
}))
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/getData', (req, res) => {
const {name, pwd} = req.body;
if (!name || !pwd) {
return res.json({
code: 200,
data: {},
errorMessage: '参数不能为空'
})
}
setTimeout(() => {
res.json({
code: 200,
data: {name, pwd},
errorMessage: '参数不能为空'
})
}, 5000);
})
app.listen(8088, () => {
console.log('server is listening 8088');
})
早期切换页签时可以将source.cancel()放在useEffect返回函数里面执行,当页签下组件销毁时就取消请求
来看看axios是如何实现请求中断的,大致原理是从外部操作中断内部promise流
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
c指cancel函数,当执行source.cancel()时从外部去操作CancelToken的私有属性resolvePromise,也就是resolve函数。
2、fetch
fetch直接使用AbortController来中断请求,详细如下:
首先安装abort-controller库,该库实现了web abort-controller。
yarn add abort-controller -S
import React, { useEffect } from 'react';
import Controller from 'abort-controller';
const AbortController = () => {
const abortController = new Controller();
useEffect(() => {
fetch('http://127.0.0.1:8088/getData', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'zs',
pwd: '123456'
}),
signal: abortController.signal
})
}, []);
const abort = () => {
abortController.abort()
}
return (
<>
this is a abortController page.
>
)
}
export default AbortController;
3、$.ajax
$.ajax内部已经实现了abort功能。
ajax(settings?: JQuery.AjaxSettings): JQuery.jqXHR;
interface jqXHR extends Promise3, never,
Ajax.SuccessTextStatus, Ajax.ErrorTextStatus, never,
jqXHR, string, never>,
Pick,
Partial> {
responseJSON?: any;
// 中断请求
abort(statusText?: string): void;
state(): 'pending' | 'resolved' | 'rejected';
statusCode(map: Ajax.StatusCodeCallbacks): void;
}
具体例子:
import React, { useEffect } from 'react';
import $ from 'jquery';
const AbortController = () => {
var abortController: JQuery.jqXHR | null = null;
useEffect(() => {
abortController = $.ajax({
url: 'http://127.0.0.1:8088/getData',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify({
name: 'zs',
pwd: '123456'
}),
success: function(res) {
console.log(res)
}
})
}, []);
const abort = () => {
abortController?.abort()
}
return (
<>
this is a abortController page.
>
)
}
export default AbortController;