Axios取消請求以及其原理(v0.26.1)
阿新 • • 發佈:2022-04-18
Axios取消請求以及其原理(v0.26.1)
1. 取消請求
const axios = require('axios') const instance = new axios.Axios({}) // 建立source,通過source.cancel()取消請求 const source = new axios.CancelToken.source() instance.defaults.timeout = 10000 instance.interceptors.request.use( config => { config.cancelToken = source.token return config } ) // 此處寫了兩個響應攔截器是測試用, // 因為我在專案中看到他人 // 定義了一個全域性的CancelToken.source。當請求失敗 // 報錯後執行source(),使config.token.reason.message = undefined // dispatchRequest時會呼叫CancelToken.prototype.throwIfRequested方法, // 直接丟擲異常資訊config.token.reason,不傳送ajax請求 instance.interceptors.response.use( ({ data, status, statusText }) => { if (status < 200 || status > 399) { throw statusText } return data } ) instance.interceptors.response.use( undefined, error => { // 取消請求 source.cancel() throw error } )
2. 取消請求的原理
呼叫 CancelToken.source.cancel方法 時,將 CancelToken例項 上的 promise 屬性的狀態改為 fulfilled
CancelToken.source方法
CancelToken.source = function source() { var cancel; // 用cancel儲存executor中的方法c方法,執行cancel()時,會將token.promise的狀態變為fulfilled var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel }; };
CancelToken建構函式
function CancelToken(executor) { // 此處省略executor須為function型別的校驗 // 用resolvePromise儲存Promise中的resolve方法,在執行source.cancel()的時候呼叫 var resolvePromise; this.promise = new Promise((resolve) => { resolvePromise = resolve; }); var token = this; // promise的狀態變為fulfilled時,遍歷_listeners並執行裡面的回撥 this.promise.then(function(cancel) { if (!token._listeners) return; var i; var l = token._listeners.length; for (i = 0; i < l; i++) { token._listeners[i](cancel); } token._listeners = null; }); // 重寫promise.then方法 // 若已取消請求,會在token.subscribe方法中執行resolve(this.reason) this.promise.then = function(onfulfilled) { var _resolve; // eslint-disable-next-line func-names var promise = new Promise(function(resolve) { token.subscribe(resolve); _resolve = resolve; }).then(onfulfilled); // 取消訂閱 promise.cancel = function reject() { token.unsubscribe(_resolve); }; return promise; }; executor(function cancel(message) { if (token.reason) { // Cancellation has already been requested return; } token.reason = new CanceledError(message); // 改變token.promise的狀態為fulfilled resolvePromise(token.reason); }); }
CancelToken.prototype.subscribe方法
/**
* 利用釋出訂閱者模式,收集回撥(執行xhr.abort方法)
*/
CancelToken.prototype.subscribe = function subscribe(listener) {
// 如果有reason,說明請求已取消,立即執行listener
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
};
明白以上邏輯後,剩下要做的就是訂閱 xhr.abort方法 。