axios之cancelToken原理以及使用

190 阅读2分钟

axios之cancelToken原理以及使用

  • 背景:工作中遇到,学习记录下,方便以后查阅

cancelToken

在真实项目中,当路由已经跳转,而上一页的请求还在pending状态,如果数据量小还好,数据量大时,跳到新页面,旧的请求依旧没有停止,这将会十分损耗性能,这时我们应该先取消掉之前还没有获得相应的请求,再跳转到页面。这里axios给我们提供了一个方法:

cancelToken其实就是用来取消Ajax请求的

基本用法

    let source = axios.CancelToken.source()
    axios.interceptors.request.use((request) => {
        request.cancelToken = source.token
        return request
    })
    router.then((lib) => {
        lib.default.beforeEach((to, from, next) => {
            source.cancel()
            source = axios.CancelToken.source()
            next()
        })
    })

取消请求之后,会进入error,在里面处理一下如果是取消请求,就不报错

    axios.interceptors.response.use(
        (response) => {
            return response
        },
        (error) => {
            if (axios.isCancel(error)) {
                console.log('request cancel', JSON.stringify(error))
                return new Promise(() => {})
            }
            return Promise.reject(error)
        }
    )

实现原理

promise只有三种状态,pending(等待),resolved(成功),rejected(失败)。

它的本质就是在解决如何取消一个已经执行的promise本身

  • 源码部分
    function Cancel(message) {
        this.message = message  // 可以传递取消请求的原因
    }
    
    function CancelToken(executor) {
        // 判断executor是一个函数,不然就报错
        if (typeof executor !== 'function') {
            throw new TypeError('executor must be a function')
        }
        
        var resolvePromise
        this.promise = new Promise(function promiseExecutor(resolve) {
            resolvePromise = resolve  // 关键代码1
        })
        
        var token = this
        // 以上token现在有一个promise属性,是一个未成功的promise对象
        executor(function cancel(message) {
            if (token.reason) {
                return
            }
            
            token.reason = new Cancel(message)
            resolvePromise(token.reason) // 关键代码2:把接收到的“取消请求信息”token.reason传递给下一个then中成功函数作为参数
        })
    }
    
    CancelToken.prototype.throwIfRequested = function throwIfRequested() {
        if(this.reason) {
            throw this.reason
        }
    }
    
    // source方法
    CancelToken.source = function source() {
        var cancel
        var token = new CancelToken(function executor(c) {
            cancel = c  // 关键代码3:实现“在他处取消请求”,与上面“终止一个promise”异曲同工
        })
        return {
            token: token,
            cancel: cancel
        }
    }
    
    module.exports = CancelToken

source()函数

source方法很简单,就是返回一个具有token和cancel属性的对象,但是token和cancel都是通过CancelToken这个构造函数来的

token

source.token是一个实例化对象,是一个未成功的promise对象

cancel()函数

source.cancel就是用来触发取消请求的函数。
cancel执行,给token加了一个reason属性,
Cancel特别简单就是给实例化对象添加一个message属性,所以现在token.reason是一个具有message属性的对象了。