这词怎么读?
官方的GitHub参考专门有人问过这个问题 #802 ,高票赞同的读法是:acks--ee--oh-ss。用中文的相似音是: 哎克 C 欧斯
如果我们去写一个网络库,需要考虑什么(只考虑web端)
1、支持哪些请求方式(get、post等)
2、请求配置(通用、自定义 eg. 超时、编码)
3、支持异步、并行
4、拦截器(请求发出前拦截、请求返回后拦截)
5、取消正在发出或未发出的请求
6、请求结果回调(正确、其他的)
先参看下axios的目录结构:
├── adapters│ ├── README.md│ ├── http.js #node环境http对象│ └── xhr.js #web环境http对象├── axios.js #入口├── cancel│ ├── Cancel.js #取消的构造对象类│ ├── CancelToken.js #取消操作的包装类│ └── isCancel.js #工具类├── core│ ├── Axios.js #Axios实例对象│ ├── InterceptorManager.js #拦截器控制器│ ├── README.md│ ├── buildFullPath.js #拼接请求的url、baseURL│ ├── createError.js #创建异常信息类工具│ ├── dispatchRequest.js #默认的拦截器(分发完全请求的拦截器)│ ├── enhanceError.js #异常信息类实体│ ├── mergeConfig.js #合并配置文件(用户设置的和默认的)│ ├── settle.js #根据http-code值来resolve/reject状态│ └── transformData.js #转转请求或相应的数据的工具类├── defaults.js #默认配置类├── helpers/ #一些帮助方法└── utils.js #通用的工具类
其核心模块主要有两个,一个是adapters 实际请求的发出的模块,另外一个就是core里面实现了一个请求从创建到完成的整个流程控制。adapters模块是对XMLHttpRequest的包装,这里不过过道的概述(主要是对一些细节的处理)。先看一下大体的流程:
接下来,我们从源码的角度来看看一个请求是如何被发出的,下面以get请求发出到收到相应为例(axios.get()):
导包
导包时发生了什么:
创建了一个axios实例,并添加了一些方法。其关键方是在createInstance():
function createInstance(defaultConfig) {// 创建一个Axios实例var context = new Axios(defaultConfig);// 为request方法bind上Axios,并方法一个包装的wrap方法:可以简单理解成创建了一个对象。之所以这样创建为了方便能 axios('https://m.zz.cn/a')这样用var instance = bind(Axios.prototype.request, context);// 把 Axios.prototype 上的方法拓展到instance上utils.extend(instance, Axios.prototype, context);// 把context中的defaults、interceptors拓展到instance实例中utils.extend(instance, context);return instance;}
导包成功后,开始调用其方法了:
axios.get(URL, {params: {foo: 'bar'}}).then(handleSuccess, handleFailure2).catch(handleFailure);
在调用get方法时是在中封装的,其内部最终会调到Axios.prototype.request指向的函数中:
Axios.prototype.request = function request(config) {/*eslint no-param-reassign:0*/// Allow for axios('example/url'[, config]) a la fetch APIif (typeof config === 'string') {config = arguments[1] || {};config.url = arguments[0];} else {config = config || {};}config = mergeConfig(this.defaults, config);// Set config.methodif (config.method) {config.method = config.method.toLowerCase();} else if (this.defaults.method) {config.method = this.defaults.method.toLowerCase();} else {config.method = 'get';}// Hook up interceptors middlewarevar chain = [dispatchRequest, undefined];var promise = Promise.resolve(config);this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {chain.unshift(interceptor.fulfilled, interceptor.rejected);});this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {chain.push(interceptor.fulfilled, interceptor.rejected);});while (chain.length) {promise = promise.then(chain.shift(), chain.shift());}return promise;};
这里面巧妙之处创建了一个请求处理链 china,创建了Promise.resolve(),然后通过promise.then()把请求链串起来。

这个请求链中有个默认添加的重要的一环dispatchRequest,它会根据不同的平台(其实在new Axios()已经确定使用哪个adapter了)来发出网络请求,并承担了对请求前后的数据包装工作。
function getDefaultAdapter() {var adapter;if (typeof XMLHttpRequest !== 'undefined') {// For browsers use XHR adapteradapter = require('./adapters/xhr');} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {// For node use HTTP adapteradapter = require('./adapters/http');}return adapter;}
接下来就是对后续拦截器的调用了,最终会回调到发起请求的地方。
