theme: orange
导读
这一系列文章记录了我在多年工作中积累的一些心得,目的是为了分享经验,并欢迎各位大佬指教,以便提升我的技术水平。
在工作中,我们经常需要与后端对接,通过接口进行数据传输,常用的网络请求库包括axios、ajax、fetch
等。那么,如何对这些库进行二次封装,以便更好地完成我们的业务开发呢?
一、为什么要进行封装
刚学习编程的新人可能会有疑问,为什么很多教程都介绍了封装网络请求的必要性?根据我的工作经验,封装网络请求主要有以下三个目的:
按照我的工作经验,封装的目的,主要是为了三个目的:
- 区分技术代码和业务代码。将技术代码独立封装,对外提供接口供业务代码调用。这样即使新人不了解底层原理,也可以快速上手,提升开发效率,并实现理想的效果。
- 方便版本升级。例如,一个老项目使用了 echarts V3,但新需求要求使用的特性只有最新版 V5 有。如果直接升级依赖,可能会导致旧代码崩溃。而通过封装,只需修改封装部分的依赖,确保兼容性即可。
- 添加新特性。在原有功能的基础上,添加适配项目需求的特性。接下来的内容将介绍如何实现这些封装。
此文章讲解的是网络的封装,我就拿ajax
来举例,将大家一步一步封装成我们自己希望的效果。因为ajax够简单
二、ajax的直接使用
$.ajax({
url: 'http://localhost:8080/ok',
type: 'get',
success: function (res) {
console.log(res); // 请求成功返回数据
},
error: function (err) {
console.log(err); // 请求失败返回数据
},
});
以上是 ajax 的基本使用,虽然简单,但存在诸多问题:
- 使用回调函数处理请求,多个请求时会形成回调地狱,可读性差。不清楚这个名词的,可以自己去搜一下。
- 环境没有区分,如开发、测试、正式环境的 URL 不同。如果 URL 写死,上线测试和正式环境时会有很多问题
- ......
这些缺点还有很多,我们先封装一个简单的函数,解决这两个问题,再继续深入。
三、 ajax的初步封装
1. 去除回调函数,改用 Promise
新建一个 request
文件夹,然后在其中新建一个 index.js
文件,作为网络封装的入口文件:
// src/utils/request/index.js
/**
* 执行AJAX请求
* @param {string} url 请求的URL
* @param {string} type 请求类型(如GET、POST等)
* @param {Object|string} data 要发送的数据
* @returns {Promise} 返回一个Promise对象,成功时resolve响应结果,失败时reject错误对象
*/
export function ajaxFunc({ url, type='get', data }) {
// 创建一个新的Promise,通过$.ajax来处理异步请求
return new Promise((resolve, reject) => {
$.ajax({
url,
type,
data,
// 请求成功时调用的回调函数
success: function (res) {
resolve(res);
},
// 请求失败时调用的回调函数
error: function (err) {
reject(err);
},
});
});
}
以上代码封装了一个函数,将 ajax 包裹在 Promise 中,使我们在使用时可以利用 async/await
解决回调地狱问题:
import { ajaxFunc } from '@/utils/request/index.js'
async function demo() {
try {
const res = await ajaxFunc({
url: 'http://localhost:8080/ok',
type: 'get',
});
console.log(res);
} catch (error) {
console.log(error);
}
}
然以上代码看起来不如直接使用简单,但在处理多个依赖顺序的请求时,差别就显而易见了。
2. 引入环境变量
我们可以引入一个变量 baseUrl
,将基础 URL 放在其中,这样只需修改这个变量即可切换环境:
// src/utils/request/index.js
// 开发环境
const baseUrl = ‘http://localhost:8080’;
/**
- 执行AJAX请求
- @param {string} url 请求的URL
- @param {string} type 请求类型(如GET、POST等)
- @param {Object|string} data 要发送的数据
@returns {Promise} 返回一个Promise对象,成功时resolve响应结果,失败时reject错误对象
*/
function ajaxFunc({ url, type = ‘get’, data }) {
const realUrl = baseUrl + url;
// 创建一个新的Promise,通过$.ajax来处理异步请求
return new Promise((resolve, reject) => {
$.ajax({
url: realUrl,
type,
data,
// 请求成功时调用的回调函数
success: function (res) {
resolve(res);
},
// 请求失败时调用的回调函数
error: function (err) {
reject(err);
},
});
});
}
在使用时,去掉前面的 IP:
import { ajaxFunc } from '@/utils/request/index.js'
async function demo() {
try {
const res = await ajaxFunc({
url: '/ok',
type: 'get',
});
console.log(res);
} catch (error) {
console.log(error);
}
}
这样,一个最简单的 ajax 封装就完成了,对于一些小项目来说已经足够。但对于大型项目,这还远远不够。下一篇文章将介绍如何在代码中处理请求错误、携带 token、取消重复请求、处理文件流等,使功能更加丰富。
这是一个从 https://juejin.cn/post/7368656101074927656 下的原始话题分离的讨论话题