axios 模拟实现

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);

	
相关推荐
程序员张39 小时前
Axios二次封装
前端·axios
zczlsy113 天前
Axios的使用
http·axios
dsl_15 天前
axios重复请求解决方案
前端·javascript·axios
USER_A0017 天前
【VUE3】练习项目——大事件后台管理
前端·vue.js·axios·pinia·elementplus·husky·vuerouter4
Json_Lee9 天前
告别Axios?试试基于`fetch`的下一代请求库 Hook-Fetch,让API调用丝滑到飞起!
http·axios
wordbaby13 天前
通过共享 Promise 解决前端重复请求-最终篇
前端·axios·promise
liyongjun63161 个月前
解析 ID 数组传参的解决方案:基于 Axios 的实现
java·javascript·vue.js·spring boot·axios·数组传参
NicolasCage1 个月前
简单的封装一下axios
vue.js·ajax·axios
每一步都算数1 个月前
Axios 请求取消:从原理到实践
axios