#vue中解决异步请求的竞态

// 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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值