/**
* Axios构造函数
* @param config
* @constructor
* config/interceptors
*/
function Axios(config) {
// 每个axios实例拥有实例属性config对象
this.config = config
// 每个axios实例拥有实例属性interceptors对象: 请求拦截器和相应拦截器
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
}
}
/**
* axios请求实例方法
* @param {*} config
* @returns
*/
Axios.prototype.request = function (config) {
// 初始化一个fulfilled状态promise 用于从执行then回掉开始
let promise = Promise.resolve(config)
// 请求拦截器+分派请求+响应拦截器的执行链
// 每次弹出两个作为promise.then的成功和失败回掉
const chains = [dispatchRequest, undefined]
// 遍历添加请求拦截器到执行链
this.interceptors.request.handlers.forEach(item => {
chains.unshift(item.fulfilled, item.rejected)
})
// 遍历添加响应拦截器到执行链
this.interceptors.response.handlers.forEach(item => {
chains.push(item.fulfilled, item.rejected)
})
// 遍历执行链 每次取出两个
while(chains.length) {
// 通过promise的then函数链 返回最终的promise结果
// fulfilled就一直调用成功回掉 出现rejected就一直调用失败回掉
promise = promise.then(chains.shift(), chains.shift())
}
return promise
}
/**
* get实例方法
* @param {*} config
*/
Axios.prototype.get = function(config) {
this.request(config)
}
/**
* post实例方法
* @param {*} config
*/
Axios.prototype.post = function(config) {
this.request(config)
}
/**
* 根据运行环境选择发送网络请求 浏览器ajax node为http
* @param {*} config
* @returns
*/
function dispatchRequest(config) {
return xhrAdapter(config)
}
/**
* 通过ajax发送网络请求
* @param {*} config
* @returns
*/
function xhrAdapter(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(config.method, config.url)
xhr.send(config.data)
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
resolve(
{
//配置对象
config: config,
//响应体
data: JSON.parse(xhr.response),
//响应头
headers: xhr.getAllResponseHeaders(), //字符串 parseHeaders
// xhr 请求对象
request: xhr,
//响应状态码
status: xhr.status,
//响应状态字符串
statusText: xhr.statusText
}
)
}else{
reject(new Error('请求失败 失败的状态码为' + xhr.status))
}
}
}
// 设置取消请求配置
if(config.cancelToken) {
config.cancelToken.promise.then(v => xhr.abort())
}
})
}
/**
* 拦截器管理对象
* @constructor
*/
function InterceptorManager() {
// 一个管理对象负责维护一个拦截器数组 每个拦截器有成功回掉和失败回掉
this.handlers = []
}
/**
* 拦截器管理对象添加拦截器
* @param {*} fulfilled
* @param {*} rejected
*/
InterceptorManager.prototype.use = function(fulfilled, rejected) {
this.handlers.push({
fulfilled,
rejected
})
}
/**
* 创建axios函数对象
* 默认导出的axios实例 是request函数对象绑定了this为request对应的实例axios
* 将request对应的axios实例属性赋值到默认导出axios实例
* @param config
* @returns {any}
*/
function createInstance(config) {
const context = new Axios(config)
const instance = Axios.prototype.request.bind(context)
// 遍历当前对象和原型连上的属性
for(const key in context) instance[key] = context[key]
return instance
}
const axios = createInstance({method: 'GET'})
axios.create = createInstance
/**
* 请求取消
* 内部暴露出该CancelToken的属性promise的 reslove方法 给执行器回掉函数
* 传入的回掉函数接受到该resolve函数即可以自己控制该CancelToken的promise的状态
* 如果状态为fulfilled 则axios在发送请求阶段会自动调用CancelToken的promise的then回掉函数
* 然后该回掉函数执行xhr.abort()取消请求发送
* @param executor
* @constructor
*/
function CancelToken(executor) {
let resolvePromise
this.promise = new Promise(resolve => {
resolvePromise = resolve
})
function cancel() {
resolvePromise()
}
executor(cancel)
}
export {axios, CancelToken}