axios源码分析与模拟(上)

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 请求,并处理响应结果。

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值