场景
有这样一个场景:后台查询统计数据的时候,如果查询全部日期的话会很慢,比如30秒的时候,这时候不想查询全部了,想查询今天的统计数据,就是会很快的0.5秒查询完了。由于查询今天的数据请求完成了,页面显示的数据是今天的,但是等到全部日期的数据请求完成之后页面的所有数据就会又变了全部日期的数据。
大概意思如下图所示:
解决
axios
从0.22.0
版本开始就不推荐 cancel token
的方式,推荐的是 AbortController
,接下来要用AbortController
的方式去主动取消请求。
AbortController介绍:
- AbortController 接口表示一个控制器对象,允许你根据需要
中止一个或多个 Web 请求
。
- 你可以使用
AbortController.AbortController()
构造函数创建一个新的AbortController
。
- 使用
AbortSignal
对象可以完成与 DOM 请求
的通信。
简单封装axios请求一下:
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
| const request = (type) => { const abortController = new AbortController(); setTimeout(()=>{ abortController.abort(); },100) return new Promise((resolve, reject) => { axios({ url: 'http://localhost:8888/test', method: 'get', params: { type, }, signal: abortController.signal, }) .then((res) => { resolve(res); }) .catch((error) => { if (axios.isCancel(error)) { console.log('Request canceled', error.message); } else { } }); }); };
|
这样发送请求就会中止,但是当前场景是下次请求取消上次的请求,目前这样封装只会自动取消,不能人为控制,所以要将 AbortController 实例抛出去,让外部进行控制。总体代码如下:
axios封装部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const request = (type, callback) => { const abortController = new AbortController(); callback && callback(abortController); return new Promise((resolve, reject) => { axios({ url: 'http://localhost:8888/test', method: 'get', params: { type, }, signal: abortController.signal, }) .then((res) => { resolve(res); }) .catch((error) => { if (axios.isCancel(error)) { console.log('Request canceled', error.message); } else { } }); }); };
|
页面结构部分
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
| const Index = () => { const [value, setValue] = useState('all'); const [response, setResponse] = useState(''); const [abortInstance, setAbortInstance] = useState();
const changeRadio = (e) => { setValue(e.target.value); };
const submit = async () => { abortInstance && abortInstance.abort(); const res = await request(value, (abortController) => { setAbortInstance(abortController); }); setResponse(res.data.msg); };
return ( <div className="main"> <input type="radio" name="sex" value="all" checked={value === 'all'} onChange={changeRadio} /> <label>全部数据</label> <input type="radio" name="sex" value="little" checked={value === 'little'} onChange={changeRadio} /> <label>少量数据</label> <div> <button onClick={submit}>请求</button> </div> <div>{response}</div> </div> ); };
|
最终的效果: