1.创建构造函数
原始构造函数用于存储默认属性与拦截器操作
拦截器管理器构造函数InterceptorManager 主要是为了存储拦截器的失败与成功操作函数
function Axios(config) {
// 数据初始化
this.defaults = config // 默认属性
this.intercepters = { // 拦截器操作
request: new InterceptorManager(), // 用于请求前拦截
response: new InterceptorManager(), // 用于响应结果拦截
}
}
2.创建Axios构造函数的原型方法(get,post,request)
重点是request函数,主要是用promise来进行链式操作
创造promise
chain存储axios请求函数dispatchRequest,undefined(失败占位符)
请求拦截在头部插入
响应拦截在尾部插入
真实axios请求在(请求拦截)与(响应拦截)之间
先执行请求拦截再执行真是axios请求,最后执行响应拦截
while 保证全部执行
// 创建原型方法
Axios.prototype.get = function (config) {
return this.request({ ...config, method: 'GET', })
}
Axios.prototype.post = function (config) {
return this.request({ ...config, method: 'POST' })
}
Axios.prototype.request = function (config) {
console.log('发送 AJAX 请求 请求的类型为 ' + config.method);
// 发送请求
// 创建promise对象
let promise = Promise.resolve(config);
//发送请求
let chain = [dispatchRequest, undefined];//undefined进行占位
// 请求拦截
this.intercepters.request.handlers.forEach(item => {
//头部插入,后写入的先执行
chain.unshift(item.fulfilled, item.injected)
})
// debugger
//响应拦截器
this.intercepters.response.handlers.forEach(item => {
//尾部插入,后写入的后执行
chain.push(item.fulfilled, item.rejected);
});
//遍历
while (chain.length > 0) {
//保证全部执行,成功函数,失败函数
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
3.创建dispatchRequest 函数
function dispatchRequest(config) {
return xhrRequest(config).then(response => {
//响应的结果进行转换处理
//....
return response;
}, error => {
throw error;
});
}
4. xhrRequest发送请求
promise进行xhr请求
当存在cancelToken的时候进行取消操作
promise.then的执行时机是在cancel方法改变promise状态才执行
function xhrRequest(config) {
return new Promise((reslove, inject) => {
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url)
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200 && xhr.status < 300) {
reslove({
config: config,
data: xhr.response,
Headers: xhr.getAllResponseHeaders(),
request: xhr,
status: xhr.status,
statusText: xhr.statusText
})
} else {
inject(new Error('请求失败 失败的状态码为' + xhr.status))
}
}
}
//关于取消请求的处理
if (config.cancelToken) {
//对 cancelToken 对象身上的 promise 对象指定成功的回调
config.cancelToken.promise.then(value => {
xhr.abort();
console.log('请求已经被取消')
//将整体结果设置为失败
inject(new Error('请求已经被取消'))
});
}
})
}
6.拦截器管理器构造函数
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function (fulfilled, rejected) {
this.handlers.push({
fulfilled,
rejected
})
}
7.创建axios声明函数,生成axios,并将Axios的原型方法跟默认属性添加到axios上
function createInstance(config) {
// 实例化一个对象 , bind绑定this而不执行
let context = new Axios(config)
let instance = Axios.prototype.request.bind(context);
// console.log(instance)
// 将context的原型方法添加到instance上
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context)
})
// 将context中的default 与intercepters添加到instance上
Object.keys(context).forEach(key => {
instance[key] = context[key]
})
// console.dir(instance)
return instance;
}
8.绑定拦截器事件
axios.intercepters.request.use(function one(config) {
console.log('请求拦截器 成功 - 1号');
return config;
}, function one(error) {
console.log('请求拦截器 失败 - 1号');
return Promise.reject(error);
});
axios.intercepters.request.use(function two(config) {
console.log('请求拦截器 成功 - 2号');
return config;
}, function two(error) {
console.log('请求拦截器 失败 - 2号');
return Promise.reject(error);
});
// 设置响应拦截器
axios.intercepters.response.use(function (response) {
console.log('响应拦截器 成功 1号');
return response;
}, function (error) {
console.log('响应拦截器 失败 1号')
return Promise.reject(error);
});
axios.intercepters.response.use(function (response) {
console.log('响应拦截器 成功 2号')
return response;
}, function (error) {
console.log('响应拦截器 失败 2号')
return Promise.reject(error);
});
9. CancelToken 构造函数用来取消请求
创造promise,先不执行resolve成功函数,而是将resolve存储起来,将function(){resolvePromise();}作为参数传递给cancel
function CancelToken(executor){
//声明一个变量
var resolvePromise;
//为实例对象添加属性
this.promise = new Promise((resolve) => {
//将 resolve 赋值给 resolvePromise
resolvePromise = resolve
});
console.log(this.promise,'this.promise')
//调用 executor 函数
executor(function(){
//执行 resolvePromise 函数
resolvePromise();
});
}
使用
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h2 class="page-header">axios取消请求</h2>
<button class="btn btn-primary"> 发送请求 </button>
<button class="btn btn-warning"> 取消请求 </button>
</div>
<script src="./axios.js">
</script>
<script>
this.resolvePromise1 =''
let a=new Promise((resolve) => {
//将 resolve 赋值给 resolvePromise
resolvePromise1 = resolve
})
a.then(v=>{
console.log(22222222222)
})
setTimeout(()=>{
resolvePromise1()
},2000)
const btns = document.querySelectorAll('button');
//2.声明全局变量
let cancel = null;
//发送请求
btns[0].onclick = function () {
//检测上一次的请求是否已经完成
if (cancel !== null) {
//取消上一次的请求
cancel();
}
//创建 cancelToken 的值
let cancelToken = new CancelToken(function (c) {
console.log(c,'c')
cancel = c;
});
debugger
axios({
method: 'GET',
url: 'http://localhost:4000/products1',
cancelToken: cancelToken
}).then(response => {
console.log(response);
});
}
//绑定第二个事件取消请求
btns[1].onclick = function () {
cancel();
}
</script>
</body>
</html>