阅读源码分为三部
打开项目之后,我们第一步是干什么,当然是找项目入口
请看package.json的main字段指向的地址,就是项目的入口文件
具体看下core/axios文件有什么内容
//lib/axios.js
// 引入文件
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var defaults = require('./defaults');
// ...省略
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
// 常见的bind方法, 将request 方法的 this 指向 context
var instance = bind(Axios.prototype.request, context);
// ...省略
return instance;
}
// 创建实例
var axios = createInstance(defaults);
// 允许继承
axios.Axios = Axios;
// 给实例添加一些静态方法、属性
// ...省略
axios.all = function all(promises) {
return Promise.all(promises);
};
// 导出的是axios的实例,所以我们import的时候,可以直接使用,而不用new
module.exports = axios;
module.exports.default = axios;
可以看到,其实主要内容,是createInstance函数中的new Axios,其他的都是附加。
axios的all方法, 使用的是promise的all方法
接下来看Axios
路径是/core/Axios
// /lib/core/Axios.js
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
Axios.prototype.request = function request(config) {
// ...省略
};
// 为支持的请求方法提供别名
// 通过下方代码,我们可以使用axios.get(),axios.post()等方法
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
当我们使用axios.get或者其他的方法的时候,其实使用的是Axios.prototype.request,
具体来看下他干了什么
Axios.prototype.request = function request(configOrUrl, config) {
// 定义两个收集器,收集对应的request和respont的拦截时间
var requestInterceptorChain = [];
var responseInterceptorChain = [];
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
var promise;
try {
// 调用ajax
promise = dispatchRequest(newConfig);
} catch (error) {
return Promise.reject(error);
}
// 并且最终返回一个promise,包含了所有的拦截器
while (responseInterceptorChain.length) {
promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
}
return promise;
};
再来看dispatchRequest方法的实现
// lib/core/dispatchRequest.js
module.exports = function dispatchRequest(config) {
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(/**省略**/);
};
这时候你发现,TM的再套娃。
继续往下看adapter
// lib/default/index.js
function getDefaultAdapter() {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// 浏览器
adapter = require('../adapters/xhr');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// node
adapter = require('../adapters/http');
}
return adapter;
}
var defaults = {
adapter: getDefaultAdapter()
// ...省略
};
module.exports = defaults;
…
继续套娃,其实不算套娃,这里进行了环境区分,是浏览器还是node环境
先看浏览器
module.exports = function xhrAdapter(config) {
// 返回promise
return new Promise(function dispatchXhrRequest(resolve, reject) {
// 创建对象
var request = new XMLHttpRequest();
// 创建链接
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
function onloadend() {
// settle 校验一些值
settle(function _resolve(value) {
resolve(value);
done();
}, function _reject(err) {
reject(err);
done();
}, response);
}
if ('onloadend' in request) {
// 无论成功还是失败
request.onloadend = onloadend;
} else {
// 监听 readyState 变化
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// readystate 在onerror和ontimeout之前就会被调用
// 所以我们这里使用setTimeout将其放到下个tick调用
setTimeout(onloadend);
};
}
// 发送请求
request.send(requestData);
});
};
阅读总结:
axios在浏览器中,使用的是XMLHttpRequest