// composables/useFetchWithoutRace.js
import { ref } from 'vue';
import axios from 'axios';
// 定义一个可复用的 Composition 函数,处理带有竞态控制的异步请求
export function useFetchWithoutRace() {
// 定义响应式变量 `latestRequestId`,用于追踪最新请求的标识
const latestRequestId = ref(null);
// 定义异步请求函数,接收 AJAX 配置对象,返回请求结果
const fetchWithoutRace = async (ajaxConfig) => {
// 生成当前请求的唯一标识,使用时间戳确保每次请求都有不同的 ID
const requestId = Date.now();
// 更新 `latestRequestId`,标记这个请求为最新的
latestRequestId.value = requestId;
try {
// 使用传入的 ajaxConfig 发送请求,axios 会根据配置自动处理 method、url、params 等
const response = await axios(ajaxConfig);
// 检查当前请求的 ID 是否仍然是最新的
if (requestId === latestRequestId.value) {
// 如果是最新的请求,直接返回响应数据
return response.data;
}
// 如果不是最新的请求,返回 null 或抛出特定标识,避免使用旧数据
return null;
} catch (error) {
// 捕获请求中的错误,抛出以便调用者处理
console.error('Fetch error:', error);
throw error;
}
};
// 返回 `fetchWithoutRace` 方法,供组件调用
return {
fetchWithoutRace, // 请求方法,返回 Promise,包含结果或 null
};
}
在组件中使用
// 组件代码
<script>
import { ref } from 'vue';
import { useFetchWithoutRace } from '@/composables/useFetchWithoutRace';
export default {
setup() {
// 调用 useFetchWithoutRace,获取 fetchWithoutRace 方法
const { fetchWithoutRace } = useFetchWithoutRace();
// 定义响应式变量,用于存储结果
const result = ref(null);
// 定义处理输入的方法,构造 AJAX 配置对象并调用 fetchWithoutRace
const handleInput = async (value) => {
// 创建 AJAX 配置对象
const ajaxConfig = {
url: '/api/data', // 请求的 API 地址
method: 'get', // 请求方法,默认为 GET
params: { q: value }, // 查询参数,传递输入框的值
};
try {
// 调用 fetchWithoutRace,等待结果
const data = await fetchWithoutRace(ajaxConfig);
// 如果是最新请求,data 会有值;否则为 null
if (data !== null) {
result.value = data;
}
} catch (error) {
// 处理请求错误
console.log('处理错误:', error);
}
};
// 返回给模板使用的变量和方法
return {
result, // 请求结果,用于显示
handleInput, // 输入处理方法,绑定到输入框
};
},
};
</script>
<template>
<div>
<!-- 输入框,每次输入时调用 handleInput,传入输入值 -->
<input @input="handleInput($event.target.value)" placeholder="输入查询" />
<!-- 显示请求结果,result 是响应式的,数据更新时自动刷新 -->
<p>结果: {{ result }}</p>
</div>
</template>
让调用者自己管理结果, fetchWithoutRace 直接返回请求数据。
fetchWithoutRace 返回一个 Promise,成功时解析为:
如果是最新请求,返回 response.data。
如果不是最新请求,返回 null。
失败时抛出错误,交给调用者处理。
竞态控制:
依然通过 requestId 和 latestRequestId 判断,只有最新请求的结果会被返回。
非最新请求返回 null,避免旧数据干扰。
调用者控制结果:
组件中用 await fetchWithoutRace(ajaxConfig) 获取结果,然后手动赋值给 result。