Published on

axios的cancel功能源码解读

Authors
  • avatar
    Name
    noodles
    每个人的花期不同,不必在乎别人比你提前拥有

本文梳理axios中使用CancelToken来实现中断请求的源码实现. (CancelToken已经是deprecated, axios已支持AbortController实现相应的功能)

简单使用

        const CancelToken = axios.CancelToken;
        // 创建cancelToken
        const source = CancelToken.source();

        axios.get('/user/12345', {
            // 请求的时候 传入创建的cancelToken
            cancelToken: source.token
        }).catch(function (thrown) {
            if (axios.isCancel(thrown)) {
                console.log('Request canceled', thrown.message);
            } else {
                // handle error
            }
        });
        // 调用cancelToken的cancel方法 取消请求
        source.cancel('Operation canceled by the user.');

上面是axios官网的上使用CancelToken的例子,可以看到通过将创建的cancelToken传入对应的请求对象,就实现了请求控制能力暴露给外部的能力。

源码分析

XMLHttpRequest支持使用abort方法实现请求的终止,axios底层封装了XMLHttpRequest来实现请求的处理,通过将调用abort方法的能力暴露给外部就实现了请求中断的控制。axios引入了cancelToken来实现这个过程的解耦。下面从具体的源码来看实现的过程

创建cancelToken对象

    // 调用source方法 生成CancelToken 导出token和取消请求的cancel方法
    CancelToken.source = function source() {
        var cancel;
        var token = new CancelToken(function executor(c) {
            cancel = c;
        });
        return {
            token: token,
            cancel: cancel
        };
    };

    function CancelToken(executor) {
        if (typeof executor !== 'function') {
            throw new TypeError('executor must be a function.');
        }

        var resolvePromise;
        // 设置CancelToken的promise函数
        this.promise = new Promise(function promiseExecutor(resolve) {
            resolvePromise = resolve;
        });

        var token = this;
        // cancel函数的执行逻辑 在调用cancel接口的时候 执行下面的逻辑
        executor(function cancel(message) {
            if (token.reason) {
                // Cancellation has already been requested
                return;
            }

            token.reason = new Cancel(message);
            resolvePromise(token.reason);
        });
    }

cancelToken与XMLHttpRequest绑定

        // 代码是axios封装XMLHttpRequest的部分逻辑
        if (config.cancelToken) {
            // 如果传入的配置有cancelToken 就调用cancelToken的promise方法 
            // 通过promise实现控制流的流转 调用cancelToken方法的时候 将resolve时机暴露给cancelToken
            // 调用cancelToken的cancel方法时,resolve了当前的promise,控制流程回到当前的后续流程,执行request.abort()从而完成请求的终止
            config.cancelToken.then(function onCanceled(cancel) {
                if (!request) {
                    return;
                }

                request.abort();
                reject(cancel);
                // Clean up request
                request = null;
            });
        }

        if (!requestData) {
            requestData = null;
        }

        // Send the request
        request.send(requestData);

通过对实现流程的源码梳理,在类似的功能中可以利用promise来完成流程的控制。