axios源码分析与模拟(上)

avatar
作者
筋斗云
阅读量:2

axios源码分析与模拟(上)

axios对象创建过程模拟实现

//构造函数         function Axios(config){             //初始化             this.defaults=config;//为了创建default默认属性             this.intercepers={                 request:{},                 response:{}             }         }          //原型添加相关的方法         Axios.prototype.request=function(config){             console.log("发送ajax请求 请求的类型为 "+config.method);         }         Axios.prototype.get=function(config){             return this.request({method:'GET'});         }         Axios.prototype.post=function(config){             return this.request({method:'POST'});         }          //声明函数         function createInstance(config) {             //实例化一个对象             let context=new Axios(config);//context.get() context.post() 但是不能当作函数使用 context()             //创建请求函数             let instance=Axios.prototype.request.bind(context);//instance是一个函数,并且可以instance({}) 此时不能instance.get()             //将Axios.prototype 对象中的方法添加大instance函数对象中             Object.keys(Axios.prototype).forEach(key=>{                 instance[key]=Axios.prototype[key].bind(context);//this.default this.interceptors             });             console.dir(instance);             //为instance函数对象添加属性 default与interceptors             Object.keys(context).forEach(key=>{                 console.log(key);                 instance[key]=context[key];             });             return instance;         }          let axios=createInstance({method:'GET'});          //发送请求 axios既可以做函数也可以做对象         axios({method:'GET'});         axios({method:'POST'});         axios.get({});         axios.post({});  

这段代码模拟了 Axios 库的基本结构,并展示了如何使用 createInstance 函数来创建一个可用于发送请求的 Axios 实例。

  1. Axios 构造函数
function Axios(config){     // 初始化     this.defaults = config;  // 用于创建默认配置     this.intercepers = {         request: {},         response: {}     }; } 

Axios 构造函数:
function Axios(config) 定义了 Axios 构造函数,用于初始化 Axios 实例。
this.defaults = config; 将传入的配置 config 存储在 defaults 属性中,作为默认配置。
this.interceptors = { request: {}, response: {} }; 初始化 interceptors 属性,用于存储请求拦截器和响应拦截器。

  1. Axios 原型方法
Axios.prototype.request = function(config){     console.log("发送ajax请求 请求的类型为 " + config.method); } Axios.prototype.get = function(config){     return this.request({method: 'GET'}); } Axios.prototype.post = function(config){     return this.request({method: 'POST'}); } 

request 方法接受一个 config 对象,并输出请求的类型。
get 方法调用 request 方法,并指定 method 为 ‘GET’。
post 方法调用 request 方法,并指定 method 为 ‘POST’。

  1. createInstance 函数
function createInstance(config) {     // 实例化一个对象     let context = new Axios(config);     // 创建请求函数     let instance = Axios.prototype.request.bind(context);     // 将Axios.prototype对象中的方法添加到instance函数对象中     Object.keys(Axios.prototype).forEach(key => {         instance[key] = Axios.prototype[key].bind(context);     });     console.dir(instance);     // 为instance函数对象添加属性 default与interceptors     Object.keys(context).forEach(key => {         console.log(key);         instance[key] = context[key];     });     return instance; } 

createInstance 函数接受一个 config 参数并创建一个 Axios 对象 context。
创建一个绑定到 context 的 request 方法,并命名为 instance。这样 instance 就是一个函数,可以用来发送请求。
将 Axios.prototype 上的所有方法绑定到 instance 上,这样 instance 也可以调用 get 和 post 方法。
将 context 的所有属性(如 defaults 和 intercepers)也添加到 instance 上。
最后返回 instance。

  1. 使用 createInstance 函数创建 axios 实例
let axios = createInstance({method: 'GET'}); // 发送请求 axios 既可以做函数也可以做对象 axios({method: 'GET'}); axios({method: 'POST'}); axios.get({}); axios.post({}); 

axios 是通过 createInstance 创建的实例。
axios 可以像函数一样调用,例如 axios({method: ‘GET’}),这将调用 request 方法并输出请求类型。
axios 也可以像对象一样调用 get 和 post 方法,这些方法同样会调用 request 方法并输出请求类型。

模拟实现axios请求发送功能

//axios发送请求 axios Axios.prototype.request bind         //1.声明构造函数         function Axios(config){             this.config=config;         }         Axios.prototype.request=function(config){             //发送请求             //创建一个promise对象             let promise=Promise.resolve(config);             //声明一个数组             let chains=[dispatchRequest,undefined];//undefined占位             //调用then方法指定回调             let result=promise.then(chains[0],chains[1]);             /**等价于              * let result=promise.then(function dispatchRequest(config){                 console.log('dispatchRequest函数');                 },chains[1]);             */             //返回promise的结果             return result;         }          //2.dispatchRequest函数         function dispatchRequest(config){             //调用适配器发送请求             return xhrAdapter(config).then(res=>{                 //响应的结果进行转换处理                 //...                 return res;             },error=>{                 throw error;             })         }          //3.adapter适配器         function xhrAdapter(config){             //发送AJAX请求             return new Promise((resolve,reject)=>{                 //实例化对象                 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){                             //成功的状态                             resolve({                                 //配置对象                                 config:config,                                 //响应体                                 data:xhr.response,                                 //响应头                                 Headers:xhr.getAllResponseHeaders(),//字符串 parseHeaders                                 //xhr请求对象                                 request:xhr,                                 //响应状态码                                 status:xhr.status,                                 //相应状态字符串                                 statusText:xhr.statusText                             });                         }else{                             //失败的状态                             reject(new Error('请求失败 失败的状态码为 '+xhr.status));                         }                     }                 }             })         }          //4.创建axios函数         let axios=Axios.prototype.request.bind(null);         axios({             method:'GET',             url:'http://localhost:3000/posts',         }).then(res=>{             console.log(res);         }) 
  1. Axios 构造函数
function Axios(config){     this.config = config; } 

Axios 是一个构造函数,它接受一个 config 对象并将其赋值给实例的 config 属性。

  1. Axios.prototype.request 方法
Axios.prototype.request = function(config){     // 创建一个promise对象     let promise = Promise.resolve(config);     // 声明一个数组     let chains = [dispatchRequest, undefined]; // undefined 占位     // 调用then方法指定回调     let result = promise.then(chains[0], chains[1]);     // 返回promise的结果     return result; } 

request 方法接收一个 config 对象,并返回一个 Promise 对象。
它首先创建一个 resolved 状态的 Promise,传入 config 作为值。
声明一个包含 dispatchRequest 函数和 undefined 的数组 chains。
使用 then 方法为 Promise 指定成功和失败的回调函数,并返回处理后的 Promise。

  1. dispatchRequest 函数
function dispatchRequest(config){     // 调用适配器发送请求     return xhrAdapter(config).then(res => {         // 响应的结果进行转换处理         // ...         return res;     }, error => {         throw error;     }); } 

dispatchRequest 函数接收 config 对象,并调用 xhrAdapter 发送请求。
处理请求成功和失败的结果,返回一个 Promise。

  1. xhrAdapter 函数
function xhrAdapter(config){     return new Promise((resolve, reject) => {         // 发送AJAX请求         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){                     // 成功的状态                     resolve({                         // 配置对象                         config: config,                         // 响应体                         data: xhr.response,                         // 响应头                         headers: xhr.getAllResponseHeaders(), // 字符串                         // xhr请求对象                         request: xhr,                         // 响应状态码                         status: xhr.status,                         // 相应状态字符串                         statusText: xhr.statusText                     });                 } else {                     // 失败的状态                     reject(new Error('请求失败 失败的状态码为 ' + xhr.status));                 }             }         };     }); } 

xhrAdapter 函数返回一个新的 Promise,用于发送 AJAX 请求。
创建并初始化 XMLHttpRequest 对象 xhr,设置请求方法和 URL。
绑定 onreadystatechange 事件处理函数,当请求完成时检查响应状态:
成功时调用 resolve,传入响应数据。
失败时调用 reject,传入错误信息。

  1. 创建 axios 函数
let axios = Axios.prototype.request.bind(null); axios({     method: 'GET',     url: 'http://localhost:3000/posts', }).then(res => {     console.log(res); }); 

axios 是通过绑定 Axios.prototype.request 方法创建的,这样 axios 函数就可以直接调用 request 方法。
调用 axios 函数发送一个 GET 请求到 http://localhost:3000/posts。
使用 then 方法处理响应结果,输出响应数据。
总结
这段代码实现了一个简化版的 axios,核心流程如下:
创建一个 Axios 实例。
通过 axios 函数调用 request 方法,返回一个 Promise。
request 方法调用 dispatchRequest 函数。
dispatchRequest 函数调用 xhrAdapter 函数,发送 AJAX 请求。
xhrAdapter 函数处理请求的结果,并返回一个 Promise。
axios 函数调用 then 方法处理最终的响应结果。

模拟axios拦截器的实现

//构造函数         function Axios(config){             this.config=config;             this.interceptors={                 request:new InterceptorManager(),                 response:new InterceptorManager(),             }         }         //发送请求         Axios.prototype.request=function(config){             //创建一个promise对象             let promise=Promise.resolve(config);             //创建一个数组             const chains=[dispatchRequest,undefined];             //处理拦截器             //请求拦截器 将请求拦截器的回调 压入到chains的前面 request.handles=[]             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>0){                 promise=promise.then(chains.shift(),chains.shift())             }              //返回一个promise队形             return promise;         }          //发送请求         function dispatchRequest(config){             //返回一个promise队形             return new Promise((resolve,reject)=>{                 resolve({                     status:200,                     statusText:'OK',                 })             })         }                   //创建实例         let context=new Axios({});         //创造axios函数         let axios=Axios.prototype.request.bind(context);         //将context属性config interceptors属性添加到axios函数对象上         Object.keys(context).forEach(key=>{             axios[key]=context[key];         })          //拦截器管理器构造函数         function InterceptorManager(){             this.handlers=[];         }         InterceptorManager.prototype.use=function(fulfilled,rejected){             this.handlers.push({                 fulfilled,                 rejected             })         }          //以下为功能测试代码         //设置请求拦截器1 config 配置对象         axios.interceptors.request.use(function(config){             console.log("请求拦截器 success--1号");             //修改config中的参数             config.params={a:100};             return config;             // throw "抛出失败,返回失败的promise"         },function(error){             console.log("请求拦截器 fail--1号");             return Promise.reject(error);         })          //设置请求拦截器2         axios.interceptors.request.use(function(config){             console.log("请求拦截器 success--2号");             //修改 config中的参数             config.timeout=2000;             return config;             // throw "抛出失败,返回失败的promise"         },function(error){             console.log("请求拦截器 fail--2号");             return Promise.reject(error);         })          //设置响应拦截器1         axios.interceptors.response.use(function(response){             console.log("响应拦截器 成功--1号");             return response.data;         },function(error){             console.log("响应拦截器 失败--1号");             return Promise.reject(error);         })          //设置响应拦截器2         axios.interceptors.response.use(function(response){             console.log("响应拦截器 成功--2号");             return response;         },function(error){             console.log("响应拦截器 失败--2号");             return Promise.reject(error);         })              console.dir(axios);         axios({             method:'GET',             url:'http://localhost:3000/posts',         }).then(res=>{             console.log(res);         }) 

这段代码实现了一个简化版的 Axios 库,带有请求和响应拦截器功能。下面是对代码的详细解释:

  1. Axios 构造函数
function Axios(config) {     this.config = config;     this.interceptors = {         request: new InterceptorManager(),         response: new InterceptorManager(),     }; } 

Axios 构造函数初始化了一个 config 配置对象,并创建了 interceptors 对象,其中包含 request 和 response 两个拦截器管理器。

  1. Axios.prototype.request 方法
Axios.prototype.request = function(config) {     let promise = Promise.resolve(config);     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 > 0) {         promise = promise.then(chains.shift(), chains.shift());     }      return promise; }; 

request 方法用于发送请求。
promise 先初始化为传入的 config 对象。
chains 数组用于存放拦截器的处理函数。
将请求拦截器的处理函数添加到 chains 的前面,将响应拦截器的处理函数添加到 chains 的后面。
遍历 chains 数组,并依次调用 then 方法,形成拦截器链。
返回最终的 promise 对象。

  1. dispatchRequest 函数
function dispatchRequest(config) {     return new Promise((resolve, reject) => {         resolve({             status: 200,             statusText: 'OK',         });     }); } 

dispatchRequest 函数模拟发送请求,直接返回一个 resolved 的 Promise 对象,表示请求成功。

  1. 创建 Axios 实例
let context = new Axios({}); let axios = Axios.prototype.request.bind(context); Object.keys(context).forEach(key => {     axios[key] = context[key]; }); 

创建一个 Axios 实例 context。
使用 bind 方法将 request 方法绑定到 context,形成 axios 函数。
将 context 的属性(如 config 和 interceptors)复制到 axios 函数对象上。

  1. InterceptorManager 构造函数和 use 方法
function InterceptorManager() {     this.handlers = []; } InterceptorManager.prototype.use = function(fulfilled, rejected) {     this.handlers.push({ fulfilled, rejected }); } 

InterceptorManager 用于管理拦截器。
use 方法用于添加拦截器,handlers 数组存放拦截器的处理函数。

  1. 添加拦截器
axios.interceptors.request.use(function(config) {     console.log("请求拦截器 success--1号");     config.params = { a: 100 };     return config; }, function(error) {     console.log("请求拦截器 fail--1号");     return Promise.reject(error); });  axios.interceptors.request.use(function(config) {     console.log("请求拦截器 success--2号");     config.timeout = 2000;     return config; }, function(error) {     console.log("请求拦截器 fail--2号");     return Promise.reject(error); });  axios.interceptors.response.use(function(response) {     console.log("响应拦截器 成功--1号");     return response.data; }, function(error) {     console.log("响应拦截器 失败--1号");     return Promise.reject(error); });  axios.interceptors.response.use(function(response) {     console.log("响应拦截器 成功--2号");     return response; }, function(error) {     console.log("响应拦截器 失败--2号");     return Promise.reject(error); }); 

代码添加了多个请求和响应拦截器。
每个拦截器都有成功和失败的回调函数。

  1. 发送请求
axios({     method: 'GET',     url: 'http://localhost:3000/posts', }).then(res => {     console.log(res); }); 

最后使用 axios 函数发送一个 GET 请求,并处理响应结果。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!