axios源码分析与模拟(上)
axios对象创建过程模拟实现
js
//构造函数
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 实例。
- Axios 构造函数
js
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 属性,用于存储请求拦截器和响应拦截器。
- Axios 原型方法
js
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'。
- createInstance 函数
js
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。
- 使用 createInstance 函数创建 axios 实例
js
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请求发送功能
js
//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);
})
- Axios 构造函数
js
function Axios(config){
this.config = config;
}
Axios 是一个构造函数,它接受一个 config 对象并将其赋值给实例的 config 属性。
- Axios.prototype.request 方法
js
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。
- dispatchRequest 函数
js
function dispatchRequest(config){
// 调用适配器发送请求
return xhrAdapter(config).then(res => {
// 响应的结果进行转换处理
// ...
return res;
}, error => {
throw error;
});
}
dispatchRequest 函数接收 config 对象,并调用 xhrAdapter 发送请求。
处理请求成功和失败的结果,返回一个 Promise。
- xhrAdapter 函数
js
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,传入错误信息。
- 创建 axios 函数
js
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拦截器的实现
js
//构造函数
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 库,带有请求和响应拦截器功能。下面是对代码的详细解释:
- Axios 构造函数
js
function Axios(config) {
this.config = config;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager(),
};
}
Axios 构造函数初始化了一个 config 配置对象,并创建了 interceptors 对象,其中包含 request 和 response 两个拦截器管理器。
- Axios.prototype.request 方法
js
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 对象。
- dispatchRequest 函数
js
function dispatchRequest(config) {
return new Promise((resolve, reject) => {
resolve({
status: 200,
statusText: 'OK',
});
});
}
dispatchRequest 函数模拟发送请求,直接返回一个 resolved 的 Promise 对象,表示请求成功。
- 创建 Axios 实例
js
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 函数对象上。
- InterceptorManager 构造函数和 use 方法
js
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function(fulfilled, rejected) {
this.handlers.push({ fulfilled, rejected });
}
InterceptorManager 用于管理拦截器。
use 方法用于添加拦截器,handlers 数组存放拦截器的处理函数。
- 添加拦截器
js
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);
});
代码添加了多个请求和响应拦截器。
每个拦截器都有成功和失败的回调函数。
- 发送请求
js
axios({
method: 'GET',
url: 'http://localhost:3000/posts',
}).then(res => {
console.log(res);
});
最后使用 axios 函数发送一个 GET 请求,并处理响应结果。