axios某一接口失败后不调用_axios 源码系列之如何取消请求
我們在前后端交互的過程中,通常是通過請求接口來實現的,而一個頁面中的交互又非常復雜,例如需要多次頻繁請求同一個接口,或者在接口還沒返回時就要切換路由等。這些都需要對接口請求的時機或者請求接口之后進行處理,避免一些無用的請求或者接口返回順序的差異。
前兩種方式,是在發起請求前進行控制,即控制發起請求的時機,而當請求發出之后則不再控制;而最終一種方式則是取消中斷還在路上的請求,然后再發起一個新的請求,不用管發起的時機。這幾種方式也要看業務的需要,選擇最適合的即可。
我們在之前的如何實現 axios 的自定義適配器 adapter文章里,略過了 axios 是如何主動取消當前請求的。今天我們就將一下在 axios 中如何取消之前發起的請求,源碼中又是怎樣實現的。
1. 主動取消之前發起的請求
我們先來看下 axios 中取消請求的用法:
const CancelToken = axios.CancelToken;// 返回兩個字段,{ token, cancel } // token用于表示某個請求,是一個Promise類型 // cancel是一個方法,當被調用時,則取消token注入的那個請求 const source = CancelToken.source();axios.get('/user/12345', {cancelToken: source.token, // 將token注入到請求中}).catch(function (thrown) {// 判斷是否是因主動取消導致的if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);} else {// handle errorconsole.error(thrown);}});axios.post('/user/12345',{name: 'new name',},{cancelToken: source.token,} );// 主動取消請求 // cancel方法會把注入的同一個token的請求方法一并取消掉 // 上面的get和post請求都會被取消掉 // cancel the request (the message parameter is optional) source.cancel('Operation canceled by the user.');從 demo 上來看,用法很簡單,token 和 cancel 的關系對應上即可。
官方例子中還有一種取消請求的方式,這個我們放在后面講,更容易理解一些。
2. 源碼解析
取消請求的方法在 https://github.com/axios/axios/tree/master/lib/cancel 的目錄中,3 個文件:
- Cancel: Cancel 類,message 和__CANCEL__屬性,用于標識取消的某個請求;
- isCancel: 判斷當前參數是否是 Cancel 的實例;
- CancelToken: 主流程,創建 Cancel 實例和取消的方法;
我們主要來看下 CancelToken 中的整個流程。
2.1 source 方法
source 作為取消請求的入口,我們就先來看下 source 方法。
// 創建token和cancel方法 CancelToken.source = function source() {var cancel;// token為 CancelToken 的實例,包含 promise 和 reason 兩個屬性// 同時把 executor 中的參數給到 cancel// 即CancelToken有一個回調函數,而這個回調函數的參數也是一個函數// CancelToken怎么執行,我們接著看!var token = new CancelToken(function executor(c) {cancel = c;});return {token: token,cancel: cancel,}; };2.2 CancelToken
CancelToken 用來取消請求,但我理解起來,思路非常的繞,我們一點點來剖析:
function CancelToken(executor) {if (typeof executor !== 'function') {throw new TypeError('executor must be a function.');}// 創建一個Promise的實例,// 當resolvePromise執行時,this.promise變為fulfilled狀態var resolvePromise;this.promise = new Promise(function promiseExecutor(resolve) {resolvePromise = resolve;});// new一個實例時,會立即執行CancelToken的回調函數executor方法// executor的參數也是一個函數,即上面的cancel就是當前的cancel函數體// 當executor的回調函數cancel執行時,會給當前CancelToken創建一個reason屬性,這個屬性是Cancel的實例// 并執行resolvePromise方法,將reason實例穿進去;執行后this.promise變為fulfilled狀態var token = this;executor(function cancel(message) {if (token.reason) {// Cancellation has already been requestedreturn;}token.reason = new Cancel(message);resolvePromise(token.reason);}); }也就是說會先創建一個 CancelToken 的實例 token,同時,將 CancelToken 中回調函數的參數給到了 cancel。當 cancel 執行時,則 token 中的 promise 屬性則會從 pending 狀態變為 fulfilled 狀態,那么 promise 上掛載的then()方法也就可以繼續執行了。
2.3 adapter
在調用 cancel 方法后,請求中是怎么操作的呢?我們看下adapter/xhr.js中的代碼:
if (config.cancelToken) {// config.cancelToken就是上面創建的token// 當token.promise變為fulfilled狀態后,就可以執行后續的鏈式操作// Handle cancellationconfig.cancelToken.promise.then(function onCanceled(cancel) {if (!request) {return;}// 取消當前的請求request.abort();// 將Cancel的實例cancel給到rejectreject(cancel);// Clean up requestrequest = null;}); }當我們使用 axios 的 catch 捕獲內部拋出的異常時,就可以通過isCancel判斷是否是因主動取消請求導致的異常:
axios.get('/user/12345', {cancelToken: source.token, // 將token注入到請求中}).catch(function (thrown) {// 判斷是否是因主動取消導致的if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);} else {// handle errorconsole.error(thrown);}});現在再來看下 cancel 執行的整個流程,就會清晰流暢很多。
3. 取消請求的另一種方式
我們在第 1 節還留著一個問題,axios 取消請求還有另一種方式,即直接使用 CancelToken 類。
其實我們發現,source()方法,只是給我們額外又封裝了一下,簡單的返回了 token 和 cancel,但本質還是 CancelToken 中的東西。
4. 總結
在取消請求的過程中,token 要和 cancel 方法保持對應關系,即都在一個對象里;若其他的請求也要取消時,可以額外再生成一組 token 和 cancel。同時,這里還用到了 Promise 的一個機制,只有在當前 Promise 變更為 fulfilled 狀態后,才能執行后面的 then 等操作。
更多文章歡迎查看我的博客:
蚊子的前端博客?www.xiabingbao.com總結
以上是生活随笔為你收集整理的axios某一接口失败后不调用_axios 源码系列之如何取消请求的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Maven and Nexus2
- 下一篇: vue学习之路.02