傳送門:node
在Axios.prototype.request
中咱們看到,要先經過請求攔截器,才能進行請求。下面看一下dispatchRequest()
是如何實現的ios
// /lib/core/dispatchRequest.js module.exports = function dispatchRequest(config) { // 判斷是否已經取消請求 throwIfCancellationRequested(config); /* 對請求的url、headers、data進行處理 */ // 發動請求的函數,返回一個promise var adapter = config.adapter || defaults.adapter; return adapter(config).then(function onAdapterResolution(response) { // 判斷是否已經取消請求 throwIfCancellationRequested(config); // 處理返回的數據 response.data = transformData( response.data, response.headers, config.transformResponse ); return response; }, function onAdapterRejection(reason) { if (!isCancel(reason)) { // 判斷是否已經取消請求 throwIfCancellationRequested(config); // 處理返回的錯誤信息 if (reason && reason.response) { reason.response.data = transformData( reason.response.data, reason.response.headers, config.transformResponse ); } } return Promise.reject(reason); });
若是用戶有在配置中傳入adapter
,將使用defaults.adapter
,根據運行環境是瀏覽器仍是nodejs採起不一樣的請求方式。axios
// /lib/defaults.js function getDefaultAdapter() { var adapter; if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { // nodejs環境 adapter = require('./adapters/http'); } else if (typeof XMLHttpRequest !== 'undefined') { // 瀏覽器環境 adapter = require('./adapters/xhr'); } return adapter; } var defaults = { adapter: getDefaultAdapter(), /* 其餘配置 */ }; modules.exports = defaults;
/lib/adapters/http.js
與/lib/adapters/xhr.js
兩個文件導出的函數都返回一個promise,具體的實現方式就不分析了。裏面有不少http請求的細節,能夠仔細研究。segmentfault
官方文檔中的調用方法promise
const CancelToken = axios.CancelToken; const source = CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }).catch(function(thrown) { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); axios.post('/user/12345', { name: 'new name' }, { cancelToken: source.token }) // cancel the request (the message parameter is optional) source.cancel('Operation canceled by the user.');
咱們進入CancelToken
類,找到了CancelToken.source()
方法:瀏覽器
// /lib/cancel/CancelToken CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel }; };
能夠看出,CancelToken.source().token
是一個CancelToken
類的實例,CancelToken.source().cancel
是new CacelToken()
時傳入參數(一個函數)的參數(也是個函數),經過CancelToken
的構造函數能夠看出:函數
// /lib/cancel/CancelToken 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().cancel
就是這個函數:源碼分析
function cancel(message) { if (token.reason) { // Cancellation has already been requested return; } token.reason = new Cancel(message); resolvePromise(token.reason); }
CancelToken.source().token
有promise
和reason
兩個屬性,promise
一直處於 pending
狀態,reason
屬性是一個Cancel
類的實例,Cancel
類的構造函數以下:post
// /lib/cancel/Cancel.js function Cancel(message) { this.message = message; } Cancel.prototype.toString = function toString() { return 'Cancel' + (this.message ? ': ' + this.message : ''); }; Cancel.prototype.__CANCEL__ = true;
在源碼中,有如下幾種方式檢測是否執行了取消請求。
1 檢測config.cancelToken
是否有reason
屬性,若是有,將reason
拋出,axios
進入rejected
狀態。ui
// /lib/core/dispatchRequest.js function throwIfCancellationRequested(config) { if (config.cancelToken) { config.cancelToken.throwIfRequested(); } } module.exports = function dispatchRequest(config) { // 判斷是否已經取消請求 throwIfCancellationRequested(config); /* ... */ }; // /lib/cancel/CancelToken CancelToken.prototype.throwIfRequested = function throwIfRequested() { if (this.reason) { throw this.reason; } };
2 在請求過程當中,執行CancelToken.source().token
的promise
屬性中的resolve
函數,參數是CancelToken.source().token.reason
,並將其拋出,promise進入rejected
狀態
if (config.cancelToken) { // Handle cancellation config.cancelToken.promise.then(function onCanceled(cancel) { if (!request) { return; } // 取消請求 request.abort(); // promise進入rejected reject(cancel); // Clean up request request = null; }); }
調用方法中catch
接到的thrown
,就是CancelToken.source().token.reason
。
若是在使用axios時候,只在config
中添加{cancelToken: source.token}
,而不調用source.cancel()
,則CancelToken.source().token
不會有reason
屬性,CancelToken.source().token.promise
也一直是pending
狀態。請求不會取消。