jiefancis / blogs

个人博客,学习笔记(issues)
1 stars 0 forks source link

源码系列:axios如何取消request请求 #13

Open jiefancis opened 3 years ago

jiefancis commented 3 years ago

关于axios取消request请求的原理

axios是对XMLHttpRequest的封装,XMLHttpRequest是通过abort实现请求取消。XMLHttpRequest.onabort被中止后执行的函数。

axios取消xmlhttprequest的设计

对axios的abort简化版实现


// 拼接ajax get url
function buildUrl(baseURL, url, params){

    if(params) {
        params = Object.entries(params).map(([key,value]) => `${key}=${value}`).join('&')
        return `${url}?${params}`
    }

    return baseURL ? baseURL + url : url
}
// 发起ajax请求
function xhr(config){
    return new Promise((resolve, reject) => {
        const request = new XMLHttpRequest()
        const requestData = config.data
        const requestParams = config.params

        let {
            method,
            baseURL,
            url
        } = config
        url = buildUrl(baseURL,url, requestParams)

        if(config.cancelToken) {
            config.cancelToken.promise.then(reason => {
                request.abort()
            })
        }

        request.open(method.toLowerCase(), url, true)
        request.onreadystatechange = function() {
            if(request.readyState === 4) {
                request.status === 200 ? resolve(request.response) : reject(request)
            }
        }
        request.send(requestData)
    })
}

function CancelToken(excutor){
    let resolvePromise = null

    this.promise = new Promise((resolve, reject) => {
        resolvePromise = resolve
    })

    // cancelToken.promise的resolve操作外放至source.cancel函数中
    excutor(function(){
        resolvePromise()
    })

}
CancelToken.source = function(){
    let cancel = undefined;
    let token = new CancelToken(function excutor(c){
        cancel = c
    })
    return {
        cancel,
        token
    }
}

const source = CancelToken.source()
xhr({
    method: 'get',
    url: 'https://plugins.kancloud.cn/api/plugin/info',
    cancelToken: source.token,
    params: {
        book: 26419,
        name: 'theme-default,highlight'
    }
}).then(res => {
    console.log('res', res)
}).catch(err => {
    console.log('err', err)
})
setTimeout(() => {
    source.cancel()
},50)