Bootstrap

axios源码分析与模拟(下)

axios源码分析与模拟(下)

模拟实现axios取消请求功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- CSS -->
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
    <!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.7.2/axios.min.js"></script> -->
</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>
        //构造函数
        function Axios(config){
            this.config=config;
        }
        //原型request方法
        Axios.prototype.request=function(config){
            return dispatchRequest(config);
        }
        //dispatchRequest函数
        function dispatchRequest(config){
            return xhrAdapter(config);
        }
        //xhrAdapter
        function xhrAdapter(config){
            //发送AJAX请求
            return new Promise((resolve,reject)=>{
                //实例化对象
                const 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({
                                //响应状态码
                                status:xhr.status,
                                //相应状态字符串
                                statusText:xhr.statusText
                            });
                        }else{
                            //失败的状态
                            reject(new Error('请求失败 失败的状态码为 '+xhr.status));
                        }
                    }
                }
                //关于取消请求的处理
                if(config.cancelToken){
                    //对cancelToken对象身上的promise对象指定成功的回调
                    config.cancelToken.promise.then(value=>{
                        xhr.abort();
                        //将整体结果设置为失败
                        reject(new Error('请求已经被取消'));
                    })
                    
                }
                
            })
        }

        //创建axios函数
        const context=new Axios({});
        const axios=Axios.prototype.request.bind(context);

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


        //获取按钮 以上为模拟实现请求取消
        const btns=document.querySelectorAll('button');
        //声明全局变量
        let cancel=null;
        // 发送请求
        btns[0].onclick = function() {
            // 检测上一次的请求是否已经完成
            if (cancel !== null) {
                // 取消上一次的请求
                cancel();
            }
            //创建cancelToken的值
            let cancelToken=new CancelToken(function(c){
                    // 将c的值赋值给cancel
                    cancel = c;
                }
            )
            axios({
                method: 'GET',
                url: 'http://localhost:3000/posts',
                // 添加配置对象的属性
                // cancelToken: cancelToken
            }).then(res => {
                console.log(res);
                // 将cancel的值初始化
                cancel = null;
            }).catch(error => {
                if (axios.isCancel(error)) {
                    console.log('Request canceled', error.message);
                } else {
                    console.error('Request failed', error);
                }
                // 将cancel的值初始化
                cancel = null;
            });
        }

        // 取消请求
        btns[1].onclick = function() {
            if (typeof cancel === 'function') {
                cancel();
                console.log("请求已取消");
                cancel = null; // 重置cancel变量
            } else {
                console.log("没有正在进行的请求");
            }
        }
    </script>
</body>
</html>

这段代码展示了如何使用模拟的 Axios 实现请求取消功能,包括 CancelToken 的实现。下面是对代码的详细解释:

  1. HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- CSS -->
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <h2 class="page-header">axios取消请求</h2>
        <button class="btn btn-primary">发送请求</button>
        <button class="btn btn-warning">取消请求</button>
    </div>
</body>
</html>

包含两个按钮:“发送请求”和“取消请求”。

  1. Axios 构造函数和 request 方法
//构造函数
function Axios(config) {
    this.config = config;
}
//原型request方法
Axios.prototype.request = function(config) {
    return dispatchRequest(config);
}

Axios 构造函数初始化了一个配置对象 config。
request 方法调用 dispatchRequest 发送请求。

  1. dispatchRequest 函数
//dispatchRequest函数
function dispatchRequest(config) {
    return xhrAdapter(config);
}

dispatchRequest 调用 xhrAdapter 发送 AJAX 请求。

  1. xhrAdapter 函数
//xhrAdapter
function xhrAdapter(config) {
    //发送AJAX请求
    return new Promise((resolve, reject) => {
        const 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({
                        status: xhr.status,
                        statusText: xhr.statusText
                    });
                } else {
                    reject(new Error('请求失败 失败的状态码为 ' + xhr.status));
                }
            }
        };
        if (config.cancelToken) {
            config.cancelToken.promise.then(value => {
                xhr.abort();
                reject(new Error('请求已经被取消'));
            });
        }
    });
}

xhrAdapter 发送 AJAX 请求并返回一个 Promise 对象。
处理请求成功和失败的情况。
检查 config 是否包含 cancelToken,如果包含,处理请求取消逻辑。

  1. 创建 axios 实例
//创建axios函数
const context = new Axios({});
const axios = Axios.prototype.request.bind(context);

创建 Axios 实例并绑定 request 方法。

  1. CancelToken 构造函数
//CancelToken构造函数
function CancelToken(executor) {
    var resolvePromise;
    this.promise = new Promise((resolve) => {
        resolvePromise = resolve;
    });
    executor(function() {
        resolvePromise();
    });
}

CancelToken 用于创建一个取消令牌。
executor 函数接受一个 cancel 函数,并在需要时调用 resolvePromise 取消请求。

  1. 处理按钮点击事件
const btns = document.querySelectorAll('button');
let cancel = null;

// 发送请求
btns[0].onclick = function() {
    if (cancel !== null) {
        cancel();
    }
    let cancelToken = new CancelToken(function(c) {
        cancel = c;
    });
    axios({
        method: 'GET',
        url: 'http://localhost:3000/posts',
        cancelToken: cancelToken
    }).then(res => {
        console.log(res);
        cancel = null;
    }).catch(error => {
        if (axios.isCancel && axios.isCancel(error)) {
            console.log('Request canceled', error.message);
        } else {
            console.error('Request failed', error);
        }
        cancel = null;
    });
}

// 取消请求
btns[1].onclick = function() {
    if (typeof cancel === 'function') {
        cancel();
        console.log("请求已取消");
        cancel = null;
    } else {
        console.log("没有正在进行的请求");
    }
}

获取按钮并添加点击事件处理程序。
在发送请求时,检查并取消上一次未完成的请求。
创建 CancelToken 实例并在请求配置中添加 cancelToken 属性。
在“取消请求”按钮点击时调用 cancel 函数取消请求。
总结
这段代码通过实现一个模拟的 Axios 库,演示了如何使用 CancelToken 来取消请求。具体步骤包括:
创建并绑定 Axios 实例。s
发送 AJAX 请求并处理结果。
实现 CancelToken 构造函数及其逻辑。
在用户交互中处理请求的发送和取消。

;