这里,我们使用一个请求接口 callAskRecordList
,它会从 /gpt/catalog
获取数据。这个接口封装了一个基于 get
的异步请求,同时为请求头添加了 Authorization
令牌,确保用户身份验证。
import { useUserStore } from '@/store' // 引入用户存储,用于获取用户信息
import { get } from "@/utils/request/get"; // 引入封装好的 GET 请求方法
// 查询参数方法,用泛型 以支持灵活的数据类型
export function callAskRecordList() {
const userStore = useUserStore(); // 获取用户存储中的数据
return get({
// 设置请求的 URL 地址
url: '/gpt/catalog',
// 设置请求头,包含 Bearer 令牌进行身份验证
headers: { Authorization: `Bearer ` + userStore.userInfo.token },
});
}
// 去掉注释
import { useAuthStore, useSettingStore, useUserStore } from '@/store'
import { get } from "@/utils/request/get";
export function callAskRecordList() {
const userStore = useUserStore();
return get({
url: '/gpt/catalog',
headers: { Authorization: `Bearer ` + userStore.userInfo.token },
})
}
接下来我们在 Vue 组件中直接使用这个接口。我们在 onMounted
生命周期钩子中触发异步请求,获取数据并更新组件的状态。在这个例子中,我们定义了一个 leftList
,用于存储从后端获取的数据。
// 引入 Vue 中的 ref 进行响应式数据声明,引入 onMounted 钩子
import { ref, onMounted } from "vue";
// 引入我们定义的接口方法
import { callAskRecordList } from "@/api/userAsk.js";
// 定义一个响应式数据 leftList,用来存储从接口获取的数据
const leftList = ref([]);
// 定义异步函数,用于调用接口并更新数据
async function callSideList() {
try {
// 使用 await 等待异步请求结果,确保 res 是 Promise 的结果
const res = await callAskRecordList();
if (res && res.data) { // 判断返回结果是否存在,以及是否包含数据
leftList.value = res.data; // 如果数据存在,将其赋值给 leftList
}
} catch (error) {
// 如果请求过程中出现错误,捕获并输出到控制台
console.error('Error fetching sider list:', error);
}
}
// 页面挂载时触发,调用上面定义的 callSideList 函数获取数据
onMounted(() => {
callSideList(); // 页面加载时调用异步函数
});
// 去掉注释
import { computed, ref, watch, onMounted } from "vue";
import { callAskRecordList1 } from "@/api/userAsk.js";
const leftList = ref([]);
async function callSideList() {
try {
const res = await callAskRecordList();
if (res && res.data) {
leftList.value = res.data;
}
} catch (error) {
console.error('Error fetching sider list:', error);
}
}
onMounted(() => {
callSideList();
})
async
函数中使用 .then()
有些同学习惯于在 async
函数中继续使用 .then()
语法,但这种做法可能会带来一些隐蔽的问题。比如,下面这种写法(不建议这样写):
async function callSideList() {
try {
// 使用 await 等待 Promise,但由于 .then() 没有返回,结果始终是 undefined
await callAskRecordList().then(res => {
if (res && res.data) { // 判断返回的 res 是否存在及其数据
leftList.value = res.data; // 将获取到的数据赋值给 leftList
}
});
} catch (error) {
console.error('Error fetching sider list:', error); // 捕获错误
}
}
// 去掉注释
async function callSideList() {
try {
await callAskRecordList().then(res => {
if (res && res.data) {
leftList.value = res.data;
}
});
} catch (error) {
console.error('Error fetching sider list:', error);
}
}
这样写的主要问题是 await
等待的实际上是 .then()
的返回值,而 .then()
没有显式返回一个值,默认返回 undefined
。这种情况下,await
后的表达式始终是 undefined
,容易导致代码逻辑出错。
更好的方式是(正确的做法是)直接使用 await
:
async function callSideList() {
try {
// 使用 await 直接等待 callAskRecordList 的结果,确保逻辑清晰
const res = await callAskRecordList();
if (res && res.data) { // 判断返回的 res 是否包含数据
leftList.value = res.data; // 将数据赋值给 leftList
}
} catch (error) {
console.error('Error fetching sider list:', error); // 捕获错误
}
}
// 去掉注释
async function callSideList() {
try {
const res = await callAskRecordList();
if (res && res.data) {
leftList.value = res.data;
}
} catch (error) {
console.error('Error fetching sider list:', error);
}
}
这样做的好处是:
- 代码更加简洁直观。
- 确保
await
确实等待的是请求的返回结果。- 避免由于
.then()
返回undefined
导致的潜在错误。
.then()
和 .catch()
链式调用当然,如果你不想使用 async/await
,而是选择使用传统的链式调用处理异步操作,也可以像下面这样写:
function callSideList() {
callAskRecordList()
.then((res) => { // 成功请求后处理结果
if (res && res.data) { // 判断 res 和其中的数据是否存在
leftList.value = res.data; // 将获取到的数据赋值给 leftList
}
})
.catch((error) => { // 捕获并处理请求错误
console.error('Error fetching sider list:', error);
});
}
// 去掉注释
function callSideList() {
callAskRecordList()
.then((res) => {
if (res && res.data) {
leftList.value = res.data;
}
})
.catch((error) => {
console.error('Error fetching sider list:', error);
});
}
这种写法同样是可行的,只不过代码的可读性可能不如 async/await
版本好,尤其是在处理复杂异步逻辑时,.then()
链式调用可能会导致所谓的“回调地狱”,使得代码结构变得混乱。
在 Vue.JS 中处理异步请求时,
async/await
和Promise.then()
各有优劣。对于简单的异步操作,链式调用.then()
和.catch()
可以很好地解决问题,但在更复杂的异步场景下,async/await
提供了更加直观、简洁和易于维护的写法。此外,在使用
async/await
时,确保不要在await
后面再接.then()
,避免在async
函数中同时使用.then()
和await,
这样会导致返回undefined
,可能带来不可预见的错误。遵循这些最佳实践,将有助于提升代码的可读性和健壮性,也避免了一些不必要的潜在错误。
上文中有使用到泛型 T ,这里来介绍一下泛型 T 和任意类型 any 的使用,请看
1. T
(泛型): 泛型是类型参数,用于创建可重用的函数、接口或类。在定义时并不指定具体类型,而是由调用者传入的实际类型来确定。泛型的目的是使代码更加灵活和可复用,同时保持类型安全。
例如:
function identity(arg: T): T {
return arg;
}
let num = identity(5); // T 被推断为 number
let str = identity("hello"); // T 被推断为 string
在这个例子中,identity
函数可以接受任意类型的参数,但在使用时类型是明确的,并且返回值会保留参数的类型。其中,
:泛型声明
(arg: T)
:参数类型: T
:返回类型
2. any
: any
是 TypeScript 中的一种类型,它表示任意类型。使用 any
时,TypeScript 不会对该变量进行类型检查,任何类型的值都可以赋给它,也可以从它那里获取任意类型的值。
例如:
function identityAny(arg: any): any {
return arg;
}
let num = identityAny(5); // 返回值类型是 any
let str = identityAny("hello"); // 返回值类型也是 any
这里,identityAny
函数可以接受任意类型的参数,但返回值类型也不确定,TypeScript 不会对此进行类型检查。