先來講一說「中斷請求」的實際場景,當頁面有多個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;