先来讲一说“中断请求”的实际场景,当页面有多个tab页签时,每次切换页签都会去请求数据,频繁的切换就会去请求不少次,好比A页签切换到B页签,A页签请求彻底是没必要要的,这时候能够在切换时中断请求。react
AbortController实验室功能,已经在主流浏览器实现,IE浏览器能够不支持,须要导入polyfill。jquery
AbortController
接口表示一个控制器对象,容许你根据须要停止一个或多个 Web请求。官网参考:https://developer.mozilla.org...ios
axios已经实现AbortController,具体实践以下:web
// 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 ( <> <div>this is a abortController page.</div> <div><button onClick={abort}>取消请求</button></div> </> ) } 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返回函数里面执行,当页签下组件销毁时就取消请求ajax
来看看axios是如何实现请求中断的,大体原理是从外部操做中断内部promise流express
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函数。json
fetch直接使用AbortController来中断请求,详细以下:
首先安装abort-controller库,该库实现了web abort-controller。axios
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 ( <> <div>this is a abortController page.</div> <div><button onClick={abort}>取消请求</button></div> </> ) } export default AbortController;
$.ajax内部已经实现了abort功能。promise
ajax(settings?: JQuery.AjaxSettings): JQuery.jqXHR; interface jqXHR<TResolve = any> extends Promise3<TResolve, jqXHR<TResolve>, never, Ajax.SuccessTextStatus, Ajax.ErrorTextStatus, never, jqXHR<TResolve>, string, never>, Pick<XMLHttpRequest, 'abort' | 'getAllResponseHeaders' | 'getResponseHeader' | 'overrideMimeType' | 'readyState' | 'responseText' | 'setRequestHeader' | 'status' | 'statusText'>, Partial<Pick<XMLHttpRequest, 'responseXML'>> { responseJSON?: any; // 中断请求 abort(statusText?: string): void; state(): 'pending' | 'resolved' | 'rejected'; statusCode(map: Ajax.StatusCodeCallbacks<any>): void; }
具体例子:浏览器
import React, { useEffect } from 'react'; import $ from 'jquery'; const AbortController = () => { var abortController: JQuery.jqXHR<any> | 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 ( <> <div>this is a abortController page.</div> <div><button onClick={abort}>取消请求</button></div> </> ) } export default AbortController;