这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
经过了上文的说明,我们已经知道了axios库是什么并且对axios的基础使用也有了一定的了解。
接下来,就开始对axios进行更深层次的学习了,将要去探究axios的原理,它有哪些功能?这些功能是如何实现?具体的工作流程是什么?
源码介绍
clone代码
学习axios的原理,需要先得到axios的源码内容:
git clone https://github.com/axios/axios.git
内容说明
主要目录
将源码clone下来之后,在编辑器中打开,可以看到其中的目录结构,介绍几个主要目录:
- dist目录 是axios代码打包编译之后的产物,也是在html文件中使用axios所必须的js插件依赖,包含axios.js和axios.min.js两个文件。
- exmaples目录 顾名思义,这里是axios使用实例的地方,里面包含了并发请求、get和post请求、详情数据转换、上传文件等实例
- lib目录 lib目录是核心目录,里面包含着axios的核心的代码,留后详述
- sandbox目录 沙箱,是对axios功能的测试代码所在地
核心目录
lib目录中是axios库的核心代码,包含适配器、请求取消、核心库、辅助函数等文件夹和axios.js、默认配置项、工具类等js文件。
目录结构如下:
lib
└─ adapters
├─ http.js // node 环境下利用 http 模块发起请求
├─ xhr.js // 浏览器环境下利用 xhr 发起请求
└─ cancel
├─ Cancel.js
├─ CancelToken.js
├─ isCancel.js
└─ core
├─ Axios.js // 生成 Axios 实例
├─ InterceptorManager.js // 拦截器
├─ dispatchRequest.js // 调用适配器发起请求
...
└─ helpers
├─ mergeConfig.js // 合并配置
├─ ...
├─ axios.js // 入口文件
├─ defaults.js // axios 默认配置项
├─ utils.js
源码分析
入口文件
文件指引
这里扯一句闲话,我遇到过做前端几年了还不知道从哪里查看项目启动命令和入口文件的,当时很震惊!!!是我还是别人出问题了???
在正常的Web项目中,我是首先去看项目package.json文件,里面的script部分中的指令就和项目的启动和打包有关。而入口文件则是要看webpack打包配置文件。
指引位置
在axios的代码里,从根目录下的webpack.config.js中可以看到入口文件是同目录下的index.js
var config = {
entry: './index.js',
output: {
path: __dirname + '/dist/',
filename: name + '.js',
sourceMapFilename: name + '.map',
library: 'axios',
libraryTarget: 'umd'
},
}
而在index.js中,又可以看到
module.exports = require('./lib/axios');
所以,我们第一步真正要探究的其实是lib文件夹下的axios.js
axios.js
在lib文件夹下axios.js最终导出的对象,就是我们所使用axios。
这里主要的内容可分为四部分:
- 各功能模块的导入
- 根据默认属性创建axios对象
- 给axios挂载各种属性和方法
- 导出axios
以下就根据这四部分进行学习。
功能模块导入
根据导入内容,也分为几大模块:
// 工具函数
var utils = require('./utils');
// 辅助函数
var bind = require('./helpers/bind');
// axios核心库
var Axios = require('./core/Axios');
// 合并配置对象
var mergeConfig = require('./core/mergeConfig');
// 默认属性配置
var defaults = require('./defaults');
创建axios对象
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
utils.extend(instance, Axios.prototype, context);
utils.extend(instance, context);
return instance;
}
var axios = createInstance(defaults);
-
context是Axios对象的实例。
- 自身拥有2个属性:defaults、interceptors
- 原型对象上有一些方法:request、getUri、delete、get、post、head、options、put、patch
-
instance是bind方法返回的一个原函数。
function bind(fn, thisArg) {
return function wrap() {
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
return fn.apply(thisArg, args);
};
};
也就是Axios.prototype.request的拷贝,且改变了this指向(this指向了context),并且拥有参数arguments
- 两次执行extend方法的作用是将Axios原型上的方法和context上的属性拷贝到instance上
var bind = require('./helpers/bind');
function extend(a, b, thisArg) {
forEach(b, function assignValue(val, key) {
if (thisArg && typeof val === 'function') {
a[key] = bind(val, thisArg);
} else {
a[key] = val;
}
});
return a;
}
所以最后导出的instance实际上是一个包含Axios实例属性和方法的函数
挂载属性方法
这部分的内容,在axios上挂载了许多属性和方法
axios.Axios = Axios;
// 工厂模式,用于创建新的实例
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// 扩展有关取消请求的属性
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
// 扩展有关并发请求的东西
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = require('./helpers/spread');
// 扩展错误显示
axios.isAxiosError = require('./helpers/isAxiosError');
导出axios
module.exports = axios;
// 为支持TS
module.exports.default = axios;
到这里,对于axios库入口文件的学习就搞一段落了。这里的内容是总结性的东西,很多模块的具体内容和原理还没有深入的学习和探究,需要在接下来的文章中继续学习。