以前分析了兩篇文章javascript
這篇文章,來分析下取消請求是怎麼實現的,先從一個簡單的取消請求的例子開始:java
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/get?name=xmz', {
cancelToken : source.token
}).then((response)=>{
console.log('response', response)
}).catch((error)=>{
if(axios.isCancel(error)){
console.log('取消請求傳遞的消息', error.message)
}else{
console.log('error', error)
}
})
// 取消請求
source.cancel('取消請求傳遞這條消息');
複製代碼
這就是一個簡單的取消請求的例子,那麼就從最開始的axios.CancelToken來看,先去axios/lib/axios.js
文件中。ios
axios.CancelToken = require('./cancel/CancelToken');
複製代碼
不費吹灰之力,就找到了CancelToken,在例子中咱們調用了source方法,那麼就去axios/lib/cancel/CancelToken.js
文件中看看這個source方法究竟是幹什麼的?axios
CancelToken.source = function(){
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c
})
return {
token : token,
cancel : cancel
}
}
複製代碼
source方法很簡單,就是返回一個具備token和cancel屬性的對象,可是token和cancel都是經過CancelToken這個構造函數來的,那麼還在這個文件中向上看,找到CancelToken函數。promise
function CancelToken (executor){
// ...
// 判斷executor是一個函數,否則就報錯
var resolvePromise;
this.promise = new Promise(function(resolve){
resolvePromise = resolve;
})
var token = this;
// 以上token如今有一個promise屬性,是一個未成功的promise對象;
executor(function cancel(message){
if(token.reason){
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
})
// 這個cancel函數就是 上面函數中的cancel,也就是source.cancel;
}
複製代碼
如今知道了source.cancel是一個函數,souce.token是一個實例化對象,暫時就知道這些,繼續看文章最開始的例子,接下來是去發送請求了,最下面還有一行代碼是執行souce.cancel();函數
souce.cancel就是用來觸發取消請求的函數。post
如今再回頭來看,上面的cancel函數,cancel執行,給token加了一個reason屬性,那麼看下這個reason屬性是什麼吧,看下這個Cancel構造函數,在axios/lib/cancel/Cancel.js
文件中ui
function Cancel(message){
this.message = message
}
複製代碼
Cancel特別簡單就是給實例化對象添加一個message屬性,因此如今token.reason是一個具備message屬性的對象了。this
繼續回到cancel函數中,resolvePromise函數執行了,那麼token.promise對象,這個本來未變成,成功狀態的promise,變成了成功狀態了,而且將token.reason對象傳遞過去了。spa
簡單總結一下,執行取消函數,就是讓token的promise的狀態變成了成功;
好了,忽然發現分析中斷了,變成成功狀態又怎樣了,怎麼取消的呢?雖然如今的同步代碼都執行完了,可是請求還沒發送出去呢,咱們還要去看發送請求的函數,發送請求的過程已經在以前的文章中分析過了,傳送門,戳這裏。
在分析發送請求以前,再看下最開始的例子,和最普通的發送一個get請求仍是有一點區別的,配置對象中多了,一個cancelToken的屬性,值是token,到底起了什麼做用呢,去axios/lib/adapters/xhr.js
中一探究竟(這裏只截取其中關於cancelToken的部分)。
// 在發送請求以前,驗證了cancelToken,看來此處就是用來取消請求的;
if(config.cancelToken){
// 具體是如何取消的,是在這個判斷內定義的;
config.cancelToken.promise.then(function(cancel){
request.abort();
reject(cancel);
request = null;
})
}
// 發送請求
request.send(requestData);
複製代碼
仔細看這只是一個promise的then函數,只有在promise的狀態變成成功後纔會執行,而剛纔咱們分析了,cancel就是讓這個promise的狀態變成成功,因此若是執行了,取消請求的函數,這個then就會執行,取消發送請求,而且把發送請求的promise變成reject,被axiox.get().catch()捕獲;
流程已經清楚了,最後再總結一下:
執行cancel是讓token的promise變成成功,在真正發送請求以前,驗證token.promise的狀態是否已經變了,若是變了,就取消請求,就是這樣一個簡單的思想來進行取消請求的。