实现XMLHttpRequest的拦截,响应与中止

3,113 阅读1分钟

实现思路

  • 基于promise封装一个ajax请求
  • 添加拦截和响应功能
  • 添加中断请求功能

实现

搭建主体函数

// 请求发生器
function dispatchResquest (config) {}
function req(config){
    // 先定义promise的成功与失败的回调
    let chain = [dispatchRequest, undefined]
    // 如果有请求和响应拦截,把拦截器分别加在请求生成器的前后
    if(config.interceptor){
        chain.unshift(config.interceptor.fulfilled, config.interceptor.rejected)
    }
    if(config.adaptor){
        chain.push(config.adaptor.fulfilled, config.adaptor.rejected)
    }
    let promise = Promise.resolve(config)
    // promise会先后调用拦截器,生成器,响应器的函数
    while(chain.length){
        promise = promise.then(chain.shift(), chain.shift())
    }
}

请求发生器主体

function dispatchRequest(config){
    const promise = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        xhr.open(config.method.toUpperCase(), config.url, true)
        xhr.send()
        xhr.timeout = config.timeout
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status === 200) {
                    // 这里加一个定时器,方便后面中止请求的操作
                    setTimeout(() => resolve(xhr.responseText), 5000)
                } else{
                    reject('request error')
                }
            }
        }
    })
    return promise.then(res => res, reason => reason)
}

添加中止操作

这里的中止操作,我们用了一个发布订阅

    let call = null
    const mitt = {
        cache: {},
        on(name, func){
            this.cache[name] = func
        },
        emit(name, data){
            this.cache[name] && this.cache[name](data)
        }
    }
    function dispatchRequest(config){
    const promise = new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open(config.method.toUpperCase(), config.url, true)
        xhr.send()
        xhr.timeout = config.timeout
        // 取出函数
        if(config.cancel){
            mitt.emit('abort', function onCacel(){
                xhr.abort()
                xhr = null
                reject('[abort] request is cancel')
            })
        }
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status === 200) {
                    // 这里加一个定时器,方便后面中止请求的操作
                    setTimeout(() => resolve(xhr && xhr.responseText), 5000)
                } else{
                    reject('request error')
                }
            }
        }
    })
    return promise.then(res => res, reason => reason)
}
function req(config){
    // 先定义promise的成功与失败的回调
    let chain = [dispatchRequest, undefined]
    // 如果有请求和响应拦截,把拦截器分别加在请求生成器的前后
    if(config.intercepter){
        chain.unshift(config.intercepter.fulfilled, config.intercepter.rejected)
    }
    if(config.adaptor){
        chain.push(config.adaptor.fulfilled, config.adaptor.rejected)
    }
    if(config.cancel){
    // 存入函数
        mitt.on('abort',function(cancelfunc){
            config.cancel(cancelfunc)
        })
    }
    let promise = Promise.resolve(config)
    // promise会先后调用拦截器,生成器,响应器的函数
    while(chain.length){
        promise = promise.then(chain.shift(), chain.shift())
    }
}

最后调用一下函数

本地试验一下

    req({
        url: 'http://127.0.0.1:5500/1.json',
		method: 'GET',
		interceptor: {
			fulfilled: e => {
				console.log('拦截', e)
				return e
			}
		},
		adaptor: {
			fulfilled: e => {
				console.log('响应', e)
				return e
			}
		},
		cancel(onCancel){
			call = onCancel
		}
    })
    setTimeout(() => call && call(), 2000)

没问题