传送门: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
状态。请求不会取消。