手写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()
}