Vue中如何在所有API调用完成后显示报表按钮?
解决思路:避免旧异步请求干扰报表按钮状态
核心问题是多次点击"预算"按钮时,前一次未完成的calculateTotalsForBudgets异步请求会继续修改已清空的estimateAmounts,导致计算属性setButtons的判断逻辑失效。以下是几种可行的解决方法:
方法1:使用请求版本号过滤旧请求结果
给每次请求分配唯一标识,仅处理最新请求的返回结果,直接丢弃旧请求的响应。
代码修改:
- 在
data中新增请求标识变量:
data() { return { budgets: [], estimateAmounts: {}, currentRequestId: 0 // 新增:记录当前请求的版本号 } },
- 修改
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)取消前一次未完成的异步请求,从根源上阻止旧请求修改数据。
代码修改:
- 在
data中新增控制器实例:
data() { return { budgets: [], estimateAmounts: {}, abortController: null // 新增:请求取消控制器 } },
- 修改
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
相关产品推荐
相关产品推荐

