关于我对axios的源码理解

1.创建构造函数

原始构造函数用于存储默认属性与拦截器操作

拦截器管理器构造函数InterceptorManager 主要是为了存储拦截器的失败与成功操作函数

function Axios(config) {
    // 数据初始化
    this.defaults = config // 默认属性
    this.intercepters = { // 拦截器操作
        request: new InterceptorManager(), // 用于请求前拦截
        response: new InterceptorManager(), // 用于响应结果拦截
    }
}

2.创建Axios构造函数的原型方法(get,post,request)

重点是request函数,主要是用promise来进行链式操作

创造promise

chain存储axios请求函数dispatchRequest,undefined(失败占位符)

请求拦截在头部插入

响应拦截在尾部插入

真实axios请求在(请求拦截)与(响应拦截)之间

先执行请求拦截再执行真是axios请求,最后执行响应拦截

while 保证全部执行

// 创建原型方法

Axios.prototype.get = function (config) {
    return this.request({ ...config, method: 'GET', })
}

Axios.prototype.post = function (config) {
    return this.request({ ...config, method: 'POST' })
}

Axios.prototype.request = function (config) {
    console.log('发送 AJAX 请求 请求的类型为 ' + config.method);

    // 发送请求
    // 创建promise对象
    let promise = Promise.resolve(config);
    //发送请求
    let chain = [dispatchRequest, undefined];//undefined进行占位
    // 请求拦截
    this.intercepters.request.handlers.forEach(item => {
         //头部插入,后写入的先执行
        chain.unshift(item.fulfilled, item.injected)
    })
    // debugger
    //响应拦截器
    this.intercepters.response.handlers.forEach(item => {
        //尾部插入,后写入的后执行
        chain.push(item.fulfilled, item.rejected);
    });
    //遍历
    while (chain.length > 0) {
        //保证全部执行,成功函数,失败函数
        promise = promise.then(chain.shift(), chain.shift());
    }
    return promise;
}

3.创建dispatchRequest 函数

function dispatchRequest(config) {
    return xhrRequest(config).then(response => {
        //响应的结果进行转换处理
        //....
        return response;
    }, error => {
        throw error;
    });
}

4. xhrRequest发送请求

promise进行xhr请求

当存在cancelToken的时候进行取消操作

promise.then的执行时机是在cancel方法改变promise状态才执行

function xhrRequest(config) {
    return new Promise((reslove, inject) => {
        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) {
                    reslove({
                        config: config,
                        data: xhr.response,
                        Headers: xhr.getAllResponseHeaders(),
                        request: xhr,
                        status: xhr.status,
                        statusText: xhr.statusText
                    })

                } else {
                    inject(new Error('请求失败 失败的状态码为' + xhr.status))
                }
            }
        }
        //关于取消请求的处理
        if (config.cancelToken) {
            //对 cancelToken 对象身上的 promise 对象指定成功的回调
            config.cancelToken.promise.then(value => {
                xhr.abort();
                console.log('请求已经被取消')
                //将整体结果设置为失败
                inject(new Error('请求已经被取消'))
            });
        }
    })
}

6.拦截器管理器构造函数

function InterceptorManager() {
    this.handlers = [];
}
InterceptorManager.prototype.use = function (fulfilled, rejected) {
    this.handlers.push({
        fulfilled,
        rejected
    })
}

7.创建axios声明函数,生成axios,并将Axios的原型方法跟默认属性添加到axios上

function createInstance(config) {

    // 实例化一个对象 , bind绑定this而不执行
    let context = new Axios(config)
    let instance = Axios.prototype.request.bind(context);
    // console.log(instance)
    // 将context的原型方法添加到instance上
    Object.keys(Axios.prototype).forEach(key => {
        instance[key] = Axios.prototype[key].bind(context)

    })
    // 将context中的default 与intercepters添加到instance上
    Object.keys(context).forEach(key => {
        instance[key] = context[key]
    })

    // console.dir(instance)
    return instance;
}

8.绑定拦截器事件

axios.intercepters.request.use(function one(config) {
    console.log('请求拦截器 成功 - 1号');
    return config;
}, function one(error) {
    console.log('请求拦截器 失败 - 1号');
    return Promise.reject(error);
});

axios.intercepters.request.use(function two(config) {
    console.log('请求拦截器 成功 - 2号');
    return config;
}, function two(error) {
    console.log('请求拦截器 失败 - 2号');
    return Promise.reject(error);
});

// 设置响应拦截器
axios.intercepters.response.use(function (response) {
    console.log('响应拦截器 成功 1号');
    return response;
}, function (error) {
    console.log('响应拦截器 失败 1号')
    return Promise.reject(error);
});

axios.intercepters.response.use(function (response) {
    console.log('响应拦截器 成功 2号')
    return response;
}, function (error) {
    console.log('响应拦截器 失败 2号')
    return Promise.reject(error);
});

9. CancelToken 构造函数用来取消请求

创造promise,先不执行resolve成功函数,而是将resolve存储起来,将function(){resolvePromise();}作为参数传递给cancel

function CancelToken(executor){
    //声明一个变量
    var resolvePromise;
    //为实例对象添加属性
    this.promise = new Promise((resolve) => {
        //将 resolve 赋值给 resolvePromise
        resolvePromise = resolve
    });
    console.log(this.promise,'this.promise')
    //调用 executor 函数
    executor(function(){
        //执行 resolvePromise 函数
        resolvePromise();
    });
}

使用 

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="css/style.css" rel="stylesheet">
</head>

<body>
    <div class="container">
        <h2 class="page-header">axios取消请求</h2>
        <button class="btn btn-primary"> 发送请求 </button>
        <button class="btn btn-warning"> 取消请求 </button>
    </div>
    <script src="./axios.js">

    </script>
    <script>
        this.resolvePromise1 =''
        let a=new Promise((resolve) => {
        //将 resolve 赋值给 resolvePromise
            resolvePromise1 = resolve
        })


        a.then(v=>{
            console.log(22222222222)
        })

        setTimeout(()=>{
            resolvePromise1()
        },2000)
        const btns = document.querySelectorAll('button');
        //2.声明全局变量
        let cancel = null;
        //发送请求
        btns[0].onclick = function () {
            //检测上一次的请求是否已经完成
            if (cancel !== null) {
                //取消上一次的请求
                cancel();
            }

            //创建 cancelToken 的值
            let cancelToken = new CancelToken(function (c) {
                console.log(c,'c')
                cancel = c;
            });
            debugger
            axios({
                method: 'GET',
                url: 'http://localhost:4000/products1',
                cancelToken: cancelToken
            }).then(response => {
                console.log(response);
            });
        }
            //绑定第二个事件取消请求
            btns[1].onclick = function () {
                cancel();
            }
    </script>
</body>

</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值