You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中如何在所有API调用完成后显示报表按钮?

解决思路:避免旧异步请求干扰报表按钮状态

核心问题是多次点击"预算"按钮时,前一次未完成的calculateTotalsForBudgets异步请求会继续修改已清空的estimateAmounts,导致计算属性setButtons的判断逻辑失效。以下是几种可行的解决方法:


方法1:使用请求版本号过滤旧请求结果

给每次请求分配唯一标识,仅处理最新请求的返回结果,直接丢弃旧请求的响应。

代码修改:

  1. 在data中新增请求标识变量:
data() {
  return {
    budgets: [],
    estimateAmounts: {},
    currentRequestId: 0 // 新增:记录当前请求的版本号
  }
},
  1. 修改getBudgets方法:
async getBudgets() {
  // 生成当前请求的唯一标识
  this.currentRequestId++;
  const activeRequestId = this.currentRequestId;

  this.isLoading = true;
  this.budgets = [];
  this.estimateAmounts = {};

  const data = await api.budget.getBudgetReport({ 
    accountIds: this.accountIds.map(a => a.accountId),
    salesRepIds: this.selectedSalesReps.map(sr => sr.userId),
    startDate: this.startDate, 
    endDate: this.endDate 
  });

  // 检查是否为最新请求,不是则直接终止后续逻辑
  if (activeRequestId !== this.currentRequestId) {
    this.isLoading = false;
    return;
  }

  this.budgets = data.map(d => ({ ...d, startDate: new Date(d.startDate) }));

  let idSets = chunk(data.map(d => d.budgetId), 10);
  for (const ids of idSets) {
    api.budget.calculateTotalsForBudgets(ids, this.user.userId)
      .then(res => {
        // 仅当前请求为最新时,才更新数据
        if (activeRequestId === this.currentRequestId) {
          this.estimateAmounts = { ...this.estimateAmounts, ...res };
        }
      });
  }

  this.isLoading = false;
},

方法2:使用AbortController取消旧请求

通过浏览器原生的AbortController(或axios的CancelToken)取消前一次未完成的异步请求,从根源上阻止旧请求修改数据。

代码修改:

  1. 在data中新增控制器实例:
data() {
  return {
    budgets: [],
    estimateAmounts: {},
    abortController: null // 新增:请求取消控制器
  }
},
  1. 修改getBudgets方法:
async getBudgets() {
  // 取消上一次未完成的请求
  if (this.abortController) {
    this.abortController.abort();
  }
  this.abortController = new AbortController();

  this.isLoading = true;
  this.budgets = [];
  this.estimateAmounts = {};

  const data = await api.budget.getBudgetReport({ 
    accountIds: this.accountIds.map(a => a.accountId),
    salesRepIds: this.selectedSalesReps.map(sr => sr.userId),
    startDate: this.startDate, 
    endDate: this.endDate 
  });

  this.budgets = data.map(d => ({ ...d, startDate: new Date(d.startDate) }));
  this.isLoading = false;

  let idSets = chunk(data.map(d => d.budgetId), 10);
  for (const ids of idSets) {
    api.budget.calculateTotalsForBudgets(ids, this.user.userId, { 
      signal: this.abortController.signal // 传递取消信号
    })
      .then(res => {
        // 请求未被取消时才更新数据
        if (!this.abortController.signal.aborted) {
          this.estimateAmounts = { ...this.estimateAmounts, ...res };
        }
      })
      .catch(err => {
        // 忽略取消请求导致的错误
        if (err.name !== 'AbortError') {
          console.error('批量计算请求失败:', err);
        }
      });
  }
},

注:需要确保api.budget.calculateTotalsForBudgets支持接收signal参数(底层基于fetch或axios实现取消逻辑)。


方法3:等待所有分批请求完成后一次性更新数据

将所有分批请求通过Promise.all等待完成,一次性合并结果后更新estimateAmounts,避免中间状态导致setButtons频繁变化。

代码修改(结合方法1的版本号逻辑):

async getBudgets() {
  this.currentRequestId++;
  const activeRequestId = this.currentRequestId;

  this.isLoading = true;
  this.budgets = [];
  this.estimateAmounts = {};

  const data = await api.budget.getBudgetReport({ 
    accountIds: this.accountIds.map(a => a.accountId),
    salesRepIds: this.selectedSalesReps.map(sr => sr.userId),
    startDate: this.startDate, 
    endDate: this.endDate 
  });

  if (activeRequestId !== this.currentRequestId) {
    this.isLoading = false;
    return;
  }

  this.budgets = data.map(d => ({ ...d, startDate: new Date(d.startDate) }));

  let idSets = chunk(data.map(d => d.budgetId), 10);
  // 将所有分批请求转为Promise数组
  const calculateRequests = idSets.map(ids => api.budget.calculateTotalsForBudgets(ids, this.user.userId));

  try {
    // 等待所有请求完成
    const results = await Promise.all(calculateRequests);
    if (activeRequestId !== this.currentRequestId) return;

    // 合并所有结果
    const totalEstimates = results.reduce((acc, res) => ({ ...acc, ...res }), {});
    this.estimateAmounts = totalEstimates;
  } catch (err) {
    console.error('批量计算失败:', err);
  } finally {
    this.isLoading = false;
  }
},

内容的提问来源于stack exchange,提问作者dtthom09

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:10:21