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

JavaScript中如何优雅处理动画与数据请求的竞态条件

优雅处理动画与异步请求的同步问题

这个场景太常见了!之前做项目的时候也被这种「谁先完成谁等谁」的异步同步问题坑过,用标志位判断确实容易绕晕,用Promise来包装两个异步事件再同步等待是最干净的解决方案,哪怕你没法修改原有回调的逻辑也完全可行。

核心思路

把两个异步操作(动画结束、数据返回)都包装成Promise,然后用Promise.all()等待两者都完成后,再执行UI重新渲染——这样不管谁先完成,都会自动等另一个,完全不用手动维护状态标志。

具体代码实现

先把原有的回调式操作转换成Promise,兼容你不能修改原有回调的限制:

// 1. 把fadeOut动画包装成Promise
function fadeOutAsPromise() {
  return new Promise(resolve => {
    // 调用原动画函数,把Promise的resolve作为完成回调传入
    startFadeOutAnimation(resolve);
  });
}

// 2. 把数据请求包装成Promise(适配原有不可修改的回调)
let resolveDataPromise;
const dataPromise = new Promise(resolve => {
  // 把Promise的resolve存到外部变量,方便在原有回调里触发
  resolveDataPromise = resolve;
});

// 改造原有数据回调(不用修改原有业务逻辑,只加一行触发Promise的代码)
function callBackFunctionToRecevieDataFromService(data) {
  var receivedData = data;
  // 触发我们的Promise,把拿到的数据传出去
  resolveDataPromise(data);
  
  // 保留原有的逻辑(如果有需要的话,同步判断的部分可以删掉了)
  // if(animationStillGoingOn) { return; } else { commonFunction(); }
}

// 按钮点击事件的新逻辑
function onButtonClick() {
  // 同时启动动画和数据请求
  const animationDone = fadeOutAsPromise();
  doSomeServiceCall(); // 原有的请求函数完全不用改
  
  // 等待两个异步操作全部完成
  Promise.all([animationDone, dataPromise])
    .then(([_, receivedData]) => {
      // 这里就是两者都完成后的统一逻辑,直接渲染UI
      performReRenderOfUIComponent(receivedData);
    })
    .catch(err => {
      // 可以加个错误处理,比如请求失败或动画出错的情况
      console.error('操作失败:', err);
    });
}

为什么这比原方案好?

  • 没有冗余状态变量:不用再维护animationStillGoingOn、receivedData这些容易混乱的标志位,Promise会自动管理异步状态
  • 逻辑更直观:一眼就能看懂是「等动画和数据都准备好再渲染」,不用绕弯子看commonFunction里的嵌套判断
  • 扩展性强:如果以后要加第三个异步操作(比如另一个过渡动画),直接加到Promise.all的数组里就行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:51:03