axios之源码分析
1.源码目录结构
(1)
/
d
i
s
t
/
\color{blue}/dist/
/dist/ 👉 项目输出目录 (打包生后的目录)
(2)
/
l
i
b
/
\color{blue}/lib/
/lib/ 👉 项目源码目录
(3)
/
a
d
a
p
t
e
r
s
/
\color{blue}/adapters/
/adapters/ 👉 定义请求的适配器xhr、http
(4)
h
t
t
p
.
j
s
\color{blue}http.js
http.js 👉 实现http适配器(包装http包)
(5)
x
h
r
.
j
s
\color{blue}xhr.js
xhr.js 👉 实现xhr适配器(包装xhr对象)(真正用来发送请求的函数)
(6)
c
a
n
c
e
l
\color{blue}cancel
cancel 👉 定义取消功能
(7)
c
o
r
e
\color{blue}core
core 👉 一些核心功能
(8)
A
x
i
o
s
.
j
s
\color{blue}Axios.js
Axios.js 👉 axios的核心主类
(9)
d
i
s
p
a
t
c
h
R
e
q
u
e
s
t
.
j
s
\color{blue}dispatchRequest.js
dispatchRequest.js 👉 用来调用http请求适配器方法发送请求的函数
(10)
I
n
t
e
r
c
e
p
t
o
r
M
a
n
a
g
e
r
.
j
s
\color{blue}InterceptorManager.js
InterceptorManager.js 👉 拦截器的管理器
(11)
s
e
t
t
l
e
.
j
s
\color{blue}settle.js
settle.js 👉 根据http响应状态,改变Promise的状态
(12)
/
h
e
l
p
e
r
s
/
\color{blue}/helpers/
/helpers/ 👉 一些辅助方法
(13)
a
x
i
o
s
.
j
s
\color{blue}axios.js
axios.js 👉 对外暴露接口
(14)
d
e
f
a
u
l
t
s
.
j
s
\color{blue}defaults.js
defaults.js 👉 axios的默认配置
(15)
u
t
i
l
s
.
j
s
\color{blue}utils.js
utils.js 👉 公用工具
(16)
p
a
c
k
a
g
e
.
j
s
o
n
\color{blue}package.json
package.json 👉 项目信息
(17)
i
n
d
e
x
.
d
.
t
s
\color{blue}index.d.ts
index.d.ts 👉 配置TypeScript的声明文件
(18)
i
n
d
e
x
.
j
s
\color{blue}index.js
index.js 👉 入口文件
2.源码分析
(1)axios与Axios的关系
- 从语法上来说:axios不是Axios的实例
- 从功能上来说:axios是Axios的实例
- axios是Axios.prototype.request函数bind()返回的函数
- axios作为对象有Axios原型对象上的所有方法,有Axios对象上所有属性
(2)instance与axios的区别
相同 | 不同 |
---|---|
都是一个能发任意请求的函数:request(config) | 默认匹配的值很可能不一样 |
都有发特定请求的各种方法:get()/post()/delete() | instance没有axios后面添加的一些方法:create()/CancelToken()/all() |
都有默认配置和拦截器的属性:defaults/interceptors |
(3)axios运行的整体流程
axios、axios.create()
👇
createInstance()
👇
config 👉 执行/别名执行
👇
Axios.prototype.request
👇
request
interceptors
👇
(处理参数与默认参数/transformdata)👉 dispatchRequest
👇
adapter
👇
axios rejected 👈 yes 👈 报错/cancel 👉 no 👉 axios fulfilled
👇
response
interceptors
👇
请求的onResolved或onRejected
① 整体流程:request(config) ==> dispatchRequest(config) ==> xhrAdapter(config)
Axios.js中的部分代码👇
var chain = [dispatchRequest, undefinded];
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);
})
// 通过promise的then()串联起所有的请求拦截器/请求方法/响应拦截器
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
// 返回用来指定我们的onResolved和onRejected的promise
return promise;
理解如下👇
/*
requestInterceptors: [{fulfilled1(){}, rejected1(){}}, {fulfilled2(){}, rejected2(){}}] // 存放请求的数组:成功的,失败的 (两个)
responseInterceptors: [{fulfilled11(){}, rejected11(){}}, {fulfilled22(){}, rejected22(){}}] // 存放响应的数组:成功的,失败的 (两个)
chain = [dispatchRequest, undefinded] // 在Axios定义的数组chain
// 遍历数组存放到chain中,unshift遍历从左往右,新加入的会放在前面(请求拦截器使用该遍历);响应拦截器使用push添加到数组中
// 遍历后的数组
chain:[
fulfilled2, rejected2, fulfilled1, rejected1, // 请求拦截器————顺序倒置
dispatchRequest, undefinded //请求
fulfilled11, rejected11, fulfilled22, rejected22 // 响应拦截器————顺序还是一样
]
// promise使用while循环,then()方法将所有的请求拦截器/请求方法/响应拦截器串连
promise链回调:config
=> (fulfilled2, rejected2) => (fulfilled1, rejected1) // 请求拦截器处理
=> (dispatchRequest, undefinded) // 发请求
=> (fulfilled11, rejected11) => (fulfilled22, rejected22) // 响应拦截器处理
=> (onResolved, onRejected) // axios发请求回调
*/
② r e q u e s t ( c o n f i g ) \color{red}request(config) request(config):将请求拦截器/dispatchRequest()/响应拦截器 通过promise链串联起来,返回promise
③ d i s p a t c h R e q u e s t ( c o n f i g ) \color{red}dispatchRequest(config) dispatchRequest(config):转换请求数据 ===> 调用xhrAdapter()发请求 ===> 请求返回后转换响应数据,返回promise
④ x h r A d a p t e r ( c o n f i g ) \color{red}xhrAdapter(config) xhrAdapter(config):创建XHR对象,根据config进行相应设置,发送特定请求,并接收响应数据,返回promise
(4)axios的请求/响应拦截器
① 请求拦截器:
可以对请求进行检查或配置进行特定处理
成功的回调函数,传递的默认是config(也必须是)
失败的回调函数,传递的默认是error
② 响应拦截器:
在请求得到响应后执行的回调函数
可以对响应数据进行特定处理
成功的回调函数,传递的默认是response
失败的回调函数,传递的默认是error
(5)axios的请求/响应数据转换
① 请求转换器:对请求头和请求体数据进行特定处理的函数
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
② 响应转换器:将响应体json字符串解析为js对象或数组的函数
response.data = JSON.parse(response.data)
(6)response的整体结构
{
data,
status,
headers,
config,
request
}
(7)error的整体结构(主要的)
{
message,
response,
request
}
(8)取消未完成的请求
① 当配置了cancelToken对象时,保存cancel函数:
创建一个用于将来中断请求的cancelPromise
并定义了一个用于取消请求的cancel函数
将cancel函数传递出来
② 调用cancel()取消请求
执行cancel函数,传入错误信息message
内部会让cancelPromise变为成功,且成功的值为一个Cancel对象
在cancelPromise的成功回调中中断请求,并让发请求的promise失败,失败的reason为Cancel对象