目前为止,我已经学习了三种向网络发送异步请求的方式:XMLHttpRequest(简称XHR)、fetch和axios库。其中,前两者是浏览器自带的api,后者是一个第三方库。
XHR是比较早出现的用于在网页中发送异步请求的方式,替代了古老的在JSP中嵌入Java代码发送请求的方式。但这个api也有自己的缺点,比如最直观的就是书写起来十分繁琐,需要自己封装,虽然市面上也有很多已经封装好的XHR库,但依然不能避免它的第二个缺点,就是回调地狱。
后出现的fetch就比较好的解决了这个问题,因为它语法简单,直接调用api请求即可。而且支持Promise,这样就解决了在XHR中多重请求引发的回调地狱问题,代码简洁,易于阅读和维护。
但是即便如此,fetch也有它的不足之处:为了代码更高程度的复用性和可维护性,需要再次封装;另外,功能不够丰富,不能满足开发需求,比如没有拦截器功能;最后一点就是,fetch是浏览器支持的api,不能跨平台使用。
axios就很好解决了fetch的问题。axios底层将XHR包装成了支持Promise的对象,并且功能丰富,即开即用。但是在业务复杂的大型项目中,依然需要对axios进行封装,主要原因是为了避免日后出现优于axios的三方库,不能在所有组件中都使用axios,否则想要更换的话,重构工作是非常费时费力的。因此将axios封装为一个统一的类,只存在于一个文件中,这样axios就和这个项目低耦合了。
那么具体怎么做呢?废话不多说,直接上代码:
// request.js
/**
将axios实例封装到一个类中
构造函数传递参数baseUrl,timeout
构造函数内部将一个axios实例作为MyRequest的一个属性
同时在这个类中创建自己的方法,方法实质就是对axios方法的封装
*/
class MyRequest{
constructor(baseUrl, timeout){
this.ins = axios.create({
baseURL: baseUrl,
timeout: timeout
})
}
request(config){
return new Promise((resolve, reject)=>{
/**
在then中的res,是经过axios包装的对象,出了data是服务器返回的数据外,还有
status 表示状态码
statusText 表示状态信息
headers 响应头
config 请求的配置
request 就是请求本身
*/
this.instance
.request(config)
.then(res => resolve(res))
.catch(err => reject(err))
})
}
get(config){
return this.request({...config, method:'get'})
}
post(config) {
return this.request({ ...config, method: 'post' })
}
// 还可以封装自己的patch/put等方法,省略不写了。
}
/**
new 一个MyRequest实例并导出
这样每次使用这个自己封装的类,都会自动创建一个对象
BASEURL和TIMEOUT是一个常量,可以提出放在统一的文件中专门保管
*/
export default new MyRequest(BASEURL, TIMEOUT)
// Home.vue
<script setup>
import myRequest from '@/service/request.js'
const getTaskList = async ()=>{
const {data} = await myRequest('/api/tasks')
return data.list;
}
</script>