手写axios

代码实现是根据视频中老师讲解后,综合整理而来。视频B站地址:https://www.bilibili.com/video/BV1wr4y1K7tq?share_source=copy_web

实现目标

  • 创建axios对象
  • 发送axios请求
  • 实现axios拦截器
  • 实现axios请求取消

代码

function Axios(config) {
    this.defaults = config
    this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
    }
}
Axios.prototype.request = function (config) {
    let promise = Promise.resolve(config)
    let chains = [dispatchRequest, undefined]

    // 处理拦截器请求
    this.interceptors.request.handlers.forEach(handler => {
        chains.unshift(handler.fulfilled, handler.rejected)
    })
    this.interceptors.response.handlers.forEach(handler => {
        chains.push(handler.fulfilled, handler.rejected)
    })
    while (chains.length > 0) {
        promise = promise.then(chains.shift(), chains.shift())
    }

    return promise
}
Axios.prototype.get = function (config) {
    return this.request({ method: "GET" })
}
Axios.prototype.post = function (config) {
    return this.request({ method: "POST" })
}

// 用于处理返回的数据(暂时未对数据进行处理)
function dispatchRequest(config) {
    return xhrAdapter(config).then(response => {
        console.log('dispatchRequest:', response)
        return response
    }).catch(err => {
        console.log('dispatchRequest:', err)
    })
}

// 用于发送ajax请求
function xhrAdapter(config) {
    return new Promise((resolve, reject) => {
        let 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({
                        config,
                        data: xhr.responseText,
                        headers: xhr.getAllResponseHeaders(),
                        request: xhr,
                        status: xhr.status,
                        statusText: xhr.statusText
                    })
                } else {
                    reject("ajax请求失败,报错:" + xhr.statusText)
                }
            }
        }

        // 执行取消请求
        if (config.cancelToken) {
            config.cancelToken.promise.then(resolve => {
                xhr.abort()
            })
        }
    })
}

// 创建axios对象
function createInstance(config) {
    let context = new Axios(config)
    let instance = Axios.prototype.request.bind(context)
    Object.keys(context).forEach(key => {
        instance[key] = context[key]
    })
    Object.keys(Axios.prototype).forEach(key => {
        instance[key] = Axios.prototype[key].bind(context)
    })
    return instance
}
let axios = createInstance()

// 拦截器管理器的构造函数
function InterceptorManager() {
    this.handlers = []
}
InterceptorManager.prototype.use = function (fulfilled, rejected) {
    this.handlers.push({ fulfilled, rejected })
}

// 取消请求的构造函数
function CancelToken(handler) {
    let resolvePromise = null
    this.promise = new Promise(resolve => {
        resolvePromise = resolve
    })
    handler(function () {
        resolvePromise()
    })
}

测试

创建axios对象
console.dir(axios)
发送axios请求
axios({
    method:'GET',
    url:'http://localhost:3000/posts'
}).then(response => {
    console.log(response);
});
实现axios拦截器
terceptors.request.use(function oneReq(config) {
    console.log("请求拦截 成功 1号")
    return config
}, function oneReq(err) {
    console.log("请求拦截 失败 1号")
    return Promise.reject(err)
})
axios.interceptors.request.use(function twoReq(config) {
    console.log("请求拦截 成功 2号")
    return config
}, function twoReq(err) {
    console.log("请求拦截 失败 2号")
    return Promise.reject(err)
})
axios.interceptors.response.use(function oneRes(config) {
    console.log("响应拦截 成功 1号")
    return config
}, function oneRes(err) {
    console.log("响应拦截 失败 1号")
    return Promise.reject(err)
})
axios.interceptors.response.use(function twoRes(config) {
    console.log("响应拦截 成功 2号")
    return config
}, function twoRes(err) {
    console.log("响应拦截 失败 2号")
    return Promise.reject(err)
})

axios({
    method:'GET',
    url:'http://localhost:3000/posts'
}).then(response => {
    console.log(response);
});
实现axios请求取消
// html
<button>发送请求</button>
<button>取消请求</button>

// js
let btns = document.getElementsByTagName("button")
let cancel = null
btns[0].onclick = function () {
    let cancelToken = new CancelToken(c => {
        cancel = c
    })
    axios({
        method: 'GET',
        url: 'http://localhost:3000/posts',
        cancelToken
    }).then(response => {
        console.log(response);
    });
}
btns[1].onclick = function () {
    cancel()
}
posted @ 2022-04-14 19:52  孟冰er  阅读(89)  评论(0编辑  收藏  举报