zoukankan      html  css  js  c++  java
  • 源码分析axios(1)~源码分析、模拟axios的创建



    ■ 查看源码发现,起初axios【instance=bind(Axios.prototype.request, context);】是一个函数,

    但后续【 utils.extend(instance, Axios.prototype, context);】又给它添加上了一些方法属性。

    axios 函数对象可以调用自身axios(config)发送请求也可以调用属性的方法axios.request(config)发送请求的原理:(看学习axios必知必会(2)https://www.cnblogs.com/shan333/p/15836026.html)



    一、源码分析axios的创建

    1、查看axios的实例对象new Axios(defaultConfig);

    ① 在类Axios 发现有配置对象拦截器对象属性

    ② 在Axios.js 文件中,还发现Axios的原型:Axios.prototype动态添加了属性方法

    requestgetUri

    'delete', 'get', 'head', 'options',

    'post', 'put', 'patch'

    ■ axios的创建的源码:

    // 通过配置创建 axios 函数
    var axios = createInstance(defaults);
    
    function createInstance(defaultConfig) {
        //创建一个实例对象 context 可以调用 get  post put delete request
        var context = new Axios(defaultConfig);// context 不能当函数使用 
    	……
    }
    
    //在 Axios 类内有属性 配置对象和拦截器对象
    function Axios(instanceConfig) {
        //实例对象上的 defaults 属性为配置对象
        this.defaults = instanceConfig;
        //实例对象上有 interceptors 属性用来设置请求和响应拦截器
        this.interceptors = {
            request: new InterceptorManager(),
            response: new InterceptorManager()
        };
    }
    
    // 在Axios.js 文件中,还发现: 
    Axios.prototype.request = function request(config) {
    	……
    }
    Axios.prototype.getUri = function getUri(config) {
    	……
    }
    utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
        /*eslint func-names:0*/
        Axios.prototype[method] = function (url, config) {
    	……
       }
    }
    utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
        /*eslint func-names:0*/
        Axios.prototype[method] = function (url, data, config) {
    	……
       }
    }
    

    2、接着是instance:

    首先是通过方法bind将request方法赋值给instance(此时instance是一个函数变量);

    然后,通过方法extends 将Axios.prototype 上的方法添加到 instance身上(此时instance是一个

    “函数对象”变量);还将实例对象content的属性(配置对象拦截器对象属性)添加到instance身上

    ■ axios的创建的源码:

    function createInstance(defaultConfig) {
    //创建Axios的实例对象 context 
        var context = new Axios(defaultConfig);//context 是实例对象,不能当函数使用  
    //将request 方法的 this 指向 context 并返回新函数 (instance 与 Axios.prototype.request 代码一致)
        var instance = bind(Axios.prototype.request, context); //instance是函数,可以用作函数使用
    //将Axios的原型 Axios.prototype 的方法都添加到 instance 函数身上
       utils.extend(instance, Axios.prototype, context); //instance是"函数对象",可当函数使用,也可当对象使用
    //将实例对象content的方法和属性添加到 instance 函数身上
      utils.extend(instance, context);
    
      return instance;
    }
    

    ■ bind函数:

    //返回一个新的函数,并将新函数 this 绑定到一个对象身上
    module.exports = function bind(fn, thisArg) {
        return function wrap() {
            var args = new Array(arguments.length);
            for (var i = 0; i < args.length; i++) {
                args[i] = arguments[i];
            }
            return fn.apply(thisArg, args);
        };
    };
    

    ■ extend函数:

    function extend(a, b, thisArg) {
        forEach(b, function assignValue(val, key) {
            if (thisArg && typeof val === 'function') {
                a[key] = bind(val, thisArg);
            } else {
                a[key] = val;
            }
        });
        return a;
    }
    



    二、模拟axios的创建

    ❀ 实现调用axios(config)自身发送请求、调用axios对象的方法属性 axios.request(config)发送请求

    <script>
        //构造函数
        function Axios(config) {
        //初始化
            this.defaults = config;//default默认属性
            this.intercepters = {
                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) {
        //实例化一个对象
        var context = new Axios(config); //实例对象可以调用方法,例如 context.get() 但是不能直接当函数使用 context() ×
        var instance = Axios.prototype.request.bind(context);//instance 是一个函数,并且可以 instance({}),
        //但是因为bind返回的是一个函数(一个拥有了Axios.prototype.request() 方法的函数,而instance的参数就是Axios的实例),所以不能 instance.get()
    
        //将Axios.prototype 对象中的方法添加到instance函数中,让instance拥有get、post、request等方法属性
        Object.keys(Axios.prototype).forEach(key => {
            // console.log(key); //修改this指向context
            instance[key] = Axios.prototype[key].bind(context);
        })
    //总结一下,到此instance自身即相当于Axios原型的request方法,
    //然后又给instance的属性添加了上了Axios原型的request、get、post方法属性
    //然后调用instance自身或instance的方法属性时,修改了this指向context这个Axios实例对象
    
    //为instance函数对象添加属性 default 与 intercetors
            Object.keys(context).forEach(key => {
                instance[key] = context[key];
            })
    
         // console.dir(instance);
            return instance;
        }
    
        //测试一下axios的创建过程
        let axios = createInstance();
        //发送Ajax请求
        axios({method: 'POST'});
        axios.post({});
    </script>
    

  • 相关阅读:
    重读SQLServer技术内幕 -- 故障检测概要
    Android Studio调试React Native项目
    Android 异常处理
    第一天
    记一次"未将对象引用设置到对象的实例"问题的排查过程
    Hyper-V连接虚拟机异常,“无法进行连接,因为可能无法将凭据发送到远程计算机”
    关于TFS2012无法发送警报邮件的问题
    BaseAdapter日常的封装
    android自定义拍照
    Android系统拍照源码
  • 原文地址:https://www.cnblogs.com/shan333/p/15836507.html
Copyright © 2011-2022 走看看