axios源码分析与模拟(上)

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 实例。

  1. 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 属性,用于存储请求拦截器和响应拦截器。

  1. 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'。

  1. 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。

  1. 使用 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);
        })
  1. Axios 构造函数
js 复制代码
function Axios(config){
    this.config = config;
}

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

  1. 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。

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

dispatchRequest 函数接收 config 对象,并调用 xhrAdapter 发送请求。

处理请求成功和失败的结果,返回一个 Promise。

  1. 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,传入错误信息。

  1. 创建 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 库,带有请求和响应拦截器功能。下面是对代码的详细解释:

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

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

  1. 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 对象。

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

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

  1. 创建 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 函数对象上。

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

InterceptorManager 用于管理拦截器。

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

  1. 添加拦截器
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);
});

代码添加了多个请求和响应拦截器。

每个拦截器都有成功和失败的回调函数。

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

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

相关推荐
m0_748247552 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
eybk2 小时前
Pytorch+Mumu模拟器+萤石摄像头实现对小孩学习的监控
学习
6.942 小时前
Scala学习记录 递归调用 练习
开发语言·学习·scala
Aileen_0v02 小时前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
m0_748255023 小时前
前端常用算法集合
前端·算法
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203983 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2343 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
守护者1704 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
学会沉淀。4 小时前
Docker学习
java·开发语言·学习