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

React useEffect中Promise.resolve未等待完成即执行后续代码的原因排查

为什么useEffect中Promise.then的逻辑晚于同步TVL计算执行?

这事儿其实是JavaScript异步执行机制的锅,我来给你拆解清楚:

问题根源:异步代码的执行顺序

JavaScript是单线程的,代码执行遵循同步优先,异步延后的规则。你代码里的Promise.resolve(prices).then(...)属于异步微任务,它的回调函数不会马上执行——哪怕prices已经是一个resolved的Promise,then里的逻辑也会被放到微任务队列里,等当前所有同步代码(也就是你的part2 TVL计算逻辑)全部执行完毕之后,才会被取出来执行。

所以在你的代码里,每个lpPool的遍历过程中:

  1. 先执行part1的同步部分(拆分token符号、调用fetchTokenPrice)
  2. 直接跳到part2执行TVL计算(这时候pool的priceTokenZero和priceTokenOne还没被赋值,因为then里的逻辑还在队列里等着)
  3. 等所有同步代码都跑完了,才会逐个执行then里的价格赋值逻辑

这就导致了你看到的“TVL计算先跑”的现象。

解决方案:用async/await确保顺序

要让价格获取完成后再计算TVL,你需要把整个逻辑改成异步等待的方式。不过注意:useEffect的回调函数不能直接标记为async,所以我们要在内部定义一个async函数然后调用它:

useEffect(() => {
  // 定义异步函数处理逻辑
  const processPools = async () => {
    // 用for...of遍历,确保每个异步操作完成后再处理下一个
    for (const lpPool of mainnet.Exchanges.Pancakeswap.LpTokens) {
      const [tokenZeroSymbol, tokenOneSymbol] = lpPool.name.replace(' LP', '').split('-');
      
      // 等待价格获取完成,这里如果fetchTokenPrice本身返回Promise,就不用Promise.resolve包装了
      const [priceTokenZero, priceTokenOne] = await fetchTokenPrice(
        tokenZeroSymbol.toLowerCase(), 
        tokenOneSymbol.toLowerCase()
      );
      
      // 找到对应的pool
      const targetPool = filteredFarmPools.find(
        pool => lpPool.name.replace(' LP', '') === pool.name
      );
      
      if (targetPool) {
        // 先赋值价格
        targetPool.priceTokenZero = priceTokenZero.usd;
        targetPool.priceTokenOne = priceTokenOne.usd;
        
        // 再计算TVL,这时候价格已经存在了
        const tvl0 = (targetPool.reserveTokenZero / 10 ** 18) * targetPool.priceTokenZero;
        const tvl1 = (targetPool.reserveTokenOne / 10 ** 18) * targetPool.priceTokenOne;
        targetPool.tvl = tvl0 + tvl1;
        
        console.log('完成价格赋值和TVL计算');
      }
    }
  };

  // 调用异步函数
  processPools();
}, [filteredFarmPools]); // 必须添加依赖项,避免无限循环和过期值

额外提醒:React状态的不可变性

如果filteredFarmPools是用useState声明的状态,那你不能直接修改对象属性(比如targetPool.priceTokenZero = ...),因为React依赖状态的引用来判断是否需要重新渲染。正确的做法是创建新的数组/对象来更新状态:

// 假设filteredFarmPools是state
const [filteredFarmPools, setFilteredFarmPools] = useState([]);

// 在processPools里改成这样更新
const updatedPools = [...filteredFarmPools];
const poolIndex = updatedPools.findIndex(
  pool => lpPool.name.replace(' LP', '') === pool.name
);

if (poolIndex !== -1) {
  const tvl0 = (updatedPools[poolIndex].reserveTokenZero / 10 ** 18) * priceTokenZero.usd;
  const tvl1 = (updatedPools[poolIndex].reserveTokenOne / 10 ** 18) * priceTokenOne.usd;
  
  updatedPools[poolIndex] = {
    ...updatedPools[poolIndex],
    priceTokenZero: priceTokenZero.usd,
    priceTokenOne: priceTokenOne.usd,
    tvl: tvl0 + tvl1
  };
  
  setFilteredFarmPools(updatedPools);
}

这样修改后,React才能检测到状态变化,重新渲染组件展示正确的TVL值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 04:47:30