axios 模拟实现
包含发送请求,拦截器,取消请求
第一步 , axios模拟发送请求
javascript
//使用 xhr 发送请求
function xhr_adpter(config){
return new Promise(function handle(resolve,reject){
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url,true);
xhr.onreadystatechange = function(){
if(4 === xhr.readyState){
// 成功, 携带对应数据
if(xhr.status >= 200 && xhr.status < 300){
resolve({
config,
data:xhr.response,
status:xhr.status,
headers:xhr.getAllResponseHeaders(),
request:xhr
});
return;
}
else
reject({
data:xhr.response,
status : xhr.status
});
}
}
//只考虑Get情况
xhr.send();
});
}
// 使用http还是xhr,这里省略http发送请求
function dispatch_req(config){
/*
判断使用 http or xhr
这里只模拟xhr
*/
return xhr_adpter(config).then(res=>{
// 对响应结果做转化,这里省略转化过程,直接返回结果
return res;
},error=>{
throw error;
})
}
// 模拟实现,暂不使用
function Axios(config){
this.config = config;
}
// 请求函数
Axios.prototype.request = function(config){
let promise = Promise.resolve(config);
//为下面的拦截器做铺垫
let callbacks = [dispatch_req, null] ;
return promise.then(callbacks[0],callbacks[1]);
}
// 仅模拟
let context = new Axios({});
//绑定上下文, axios() 相当于 request()
let axios = Axios.prototype.request.bind(context);
let new_promise = axios({method:"GET",url:"http://127.0.0.1/get_axios"});
new_promise.then(res=>{
console.log("get :", res);
},error=>{
console.log("error:",error)
});
第二步,拦截器模拟
添加拦截器函数
javascript
//拦截器
function Interceptor(){
this.handlers = [];
}
Interceptor.prototype.use = function(success=null, fail=null){
this.handlers.push(
{
success,
fail
}
);
}
构造函数新增拦截器
javascript
function Axios(config){
this.config = config;
//新增拦截器
this.interceptors = {
request: new Interceptor(),
response : new Interceptor()
};
}
新增初始化函数
javascript
function prepare(){
let context = new Axios({});
//绑定上下文, axios() 相当于 request()
let axios = Axios.prototype.request.bind(context);
//增加拦截器引用属性到axios, 以方便使用
Object.keys(context).forEach(key=>{
axios[key] = context[key];
});
return axios;
}
修改请求函数
javascript
// 请求函数
Axios.prototype.request = function(config){
let promise = Promise.resolve(config);
// 保存所有回调,包含拦截器, 形成then回调
let callbacks = [dispatch_req, null] ;
/*
把拦截器加入数组
把请求拦截器 放入数组前端
把响应拦截器 放入数组后面
整个数组像这样:
[请求拦截success回调,请求拦截fail回调, dispatch_req,null, 响应拦截success,响应拦截fail]
*/
while(this.interceptors.request.handlers.length > 0){
let handler = this.interceptors.request.handlers.shift();
callbacks.unshift(handler.success, handler.fail);
}
while(this.interceptors.response.handlers.length > 0){
let handler = this.interceptors.response.handlers.shift();
callbacks.push(handler.success, handler.fail)
}
// 为数组回调生成所有promise对象
while(callbacks.length > 0){
let success = callbacks.shift();
let fail = callbacks.shift();
promise = promise.then(success,fail);
}
return promise;
}
拦截器完整代码
javascript
//拦截器
function Interceptor(){
this.handlers = [];
}
Interceptor.prototype.use = function(success=null, fail=null){
this.handlers.push(
{
success,
fail
}
);
}
//使用 xhr 发送请求
function xhr_adpter(config){
return new Promise(function handle(resolve,reject){
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url,true);
xhr.onreadystatechange = function(){
if(4 === xhr.readyState){
// 成功, 携带对应数据
if(xhr.status >= 200 && xhr.status < 300){
resolve({
config,
data:xhr.response,
status:xhr.status,
headers:xhr.getAllResponseHeaders(),
request:xhr
});
return;
}
else
reject({
data:xhr.response,
status : xhr.status
});
}
}
//只考虑Get情况
xhr.send();
});
}
function dispatch_req(config){
/*
判断使用 http or xhr
*/
return xhr_adpter(config).then(res=>{
// 对响应结果做转化,这里省略转化过程,直接返回结果
return res;
},error=>{
throw error;
})
}
function Axios(config){
this.config = config;
//新增拦截器
this.interceptors = {
request: new Interceptor(),
response : new Interceptor()
};
}
// 请求函数
Axios.prototype.request = function(config){
let promise = Promise.resolve(config);
// 保存所有回调,包含拦截器, 形成then回调
let callbacks = [dispatch_req, null] ;
/*
把拦截器加入数组
把请求拦截器 放入数组前端
把响应拦截器 放入数组后面
整个数组像这样:
[请求拦截success回调,请求拦截fail回调, dispatch_req,null, 响应拦截success,响应拦截fail]
*/
while(this.interceptors.request.handlers.length > 0){
let handler = this.interceptors.request.handlers.shift();
callbacks.unshift(handler.success, handler.fail);
}
while(this.interceptors.response.handlers.length > 0){
let handler = this.interceptors.response.handlers.shift();
callbacks.push(handler.success, handler.fail)
}
// 为数组回调生成所有promise对象
while(callbacks.length > 0){
let success = callbacks.shift();
let fail = callbacks.shift();
promise = promise.then(success,fail);
}
return promise;
}
// 初始化函数
function prepare(){
let context = new Axios({});
//绑定上下文, axios() 相当于 request()
let axios = Axios.prototype.request.bind(context);
//增加拦截器引用属性到axios, 以方便使用
Object.keys(context).forEach(key=>{
axios[key] = context[key];
});
return axios;
}
axios = prepare();
axios.interceptors.request.use(config=>{
console.log("请求1",config)
return config;
},error=>{});
axios.interceptors.request.use(config=>{
console.log("请求2",config)
return config;
},error=>{});
axios.interceptors.response.use(res=>{
console.log("响应1");
return res;
});
axios.interceptors.response.use(res=>{
console.log("响应2");
return res;
});
let new_promise = axios({method:"GET",url:"http://127.0.0.1/get_axios"});
new_promise.then(res=>{
console.log("get :", res);
},error=>{
console.log("error:",error)
});
添加取消请求
代码较为简单,只贴出新增代码
javascript
//取消请求
function AbortSignal(){
// 此promise的状态由外部调用
let resolve_func;
this.promise = new Promise(resolve=>{
resolve_func = resolve;
});
//添加abort函数,外部可直接调用
this.abort = resolve_func;
}
在xhr发送请求的代码中添加 取消请求的处理
javascript
//使用 xhr 发送请求
function xhr_adpter(config){
return new Promise(function handle(resolve,reject){
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url,true);
// 若配置对象中有signal属性
if(config.signal){
config.signal.promise.then(res=>{
xhr.abort();
});
}
/*
以下代码不变
*/
});
}
javascript
//创建一个取消请求的对象
let abort_signal = new AbortSignal();
let new_promise = axios({
method:"GET",
url:"http://127.0.0.1/get_axios",
signal: abort_signal //新增部分
});
new_promise.then(res=>{
console.log("get :", res);
},error=>{
console.log("error:",error)
});
setTimeout(() => {
abort_signal.abort();
}, 1000);