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

如何按不同时间间隔、不同参数顺序调用async函数实现进度条递增

问题原因

之前的实现出现进度异常、卡顿冻结主要是以下几点导致:

  • 定时器未做清理:组件卸载后仍然触发状态更新,造成内存泄漏,大量无效定时器累积就会引发卡顿
  • 请求并发无顺序控制:多个定时任务重叠触发接口请求,返回顺序不可控会导致进度条回退
  • 副作用依赖缺失:useEffect依赖为空,外部传入的订单状态变化时无法同步更新进度

正确实现方案

完整修正代码

import { useState, useEffect } from 'react';
import moment from 'moment';

// 阶段定义保持不变
const STAGES = {
  PENDING: 'Pending Order Confirmation',
  CONFIRMED: 'Order Confirmed',
  PICKING_UP: 'Picking Up',
  EXAMINING: 'Examining',
  SANITIZING: 'Sanitizing',
  RECYCLING: 'Recycling',
};

const progression = {
  [STAGES.PENDING]: 5,
  [STAGES.CONFIRMED]: 20,
  [STAGES.PICKING_UP]: 40,
  [STAGES.EXAMINING]: 60,
  [STAGES.SANITIZING]: 70,
  [STAGES.RECYCLING]: 100,
};

// 新增:阶段流转顺序
const STAGE_ORDER = [
  STAGES.PENDING,
  STAGES.CONFIRMED,
  STAGES.PICKING_UP,
  STAGES.EXAMINING,
  STAGES.SANITIZING,
  STAGES.RECYCLING
];

// 新增:每个阶段对应的距离订单创建时间的间隔秒数,可根据需求调整
const STAGE_DELAY_SECONDS = {
  [STAGES.PENDING]: 3, // 订单创建3秒后进入已确认
  [STAGES.CONFIRMED]: 10, // 订单创建10秒后进入取件中
  [STAGES.PICKING_UP]: 20, // 订单创建20秒后进入检测中
  [STAGES.EXAMINING]: 30, // 订单创建30秒后进入消毒中
  [STAGES.SANITIZING]: 45, // 订单创建45秒后进入回收完成
};

const ProgressBar = ({ order }) => {
  const { status, order_date } = order;
  const msTillXSeconds = (seconds) => {
    const targetTime = new Date(moment(order_date).add(seconds, 'seconds')).getTime();
    const diff = targetTime - Date.now();
    // 兜底:如果已经过了目标时间,直接返回0立即执行
    return diff > 0 ? diff : 0;
  };

  const [progress, setProgress] = useState(progression[status]);
  const [internalStatus, setInternalStatus] = useState(status);

  const updateStatus = async (newStatus) => {
    try {
      const body = { status: newStatus };
      const response = await fetch(`http://localhost:5000/orders/${order.order_id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json', token: localStorage.token },
        body: JSON.stringify(body),
      });
      if (response.ok) {
        setProgress(progression[newStatus]);
        setInternalStatus(newStatus);
      }
    } catch (err) {
      console.error(err.message);
    }
  };
  
  useEffect(() => {
    // 已经到最终阶段,停止调度
    if (internalStatus === STAGES.RECYCLING) return;

    const currentStageIndex = STAGE_ORDER.indexOf(internalStatus);
    // 阶段不存在的异常处理
    if (currentStageIndex === -1 || currentStageIndex >= STAGE_ORDER.length - 1) return;

    const nextStage = STAGE_ORDER[currentStageIndex + 1];
    const delayMs = msTillXSeconds(STAGE_DELAY_SECONDS[internalStatus]);

    // 设置定时器,延迟到指定时间后更新到下一个阶段
    const timerId = setTimeout(async () => {
      await updateStatus(nextStage);
    }, delayMs);

    // 清理函数:组件卸载/依赖变化时清空定时器,避免无效执行
    return () => clearTimeout(timerId);
  }, [internalStatus, order_date]);

  // 同步外部传入的status
  useEffect(() => {
    setProgress(progression[status]);
    setInternalStatus(status);
  }, [status]);

  return (
    <>
      <div className="progress">
        <div
          className="progress-bar progress-bar-striped progress-bar-animated"
          role="progressbar"
          style={{ width: `${progress}%` }}
        >
        </div>
      </div>
      <p className="text-center my-1">{internalStatus}</p>
    </>
  );
};

核心优化点

  • 明确了阶段流转的顺序,不会出现跳阶段的异常
  • 所有定时器都有对应的清理逻辑,组件卸载时会自动清空未执行的任务,彻底解决内存泄漏和卡顿问题
  • 采用串行执行逻辑,前一个阶段的接口请求完成后才会调度下一个阶段,避免请求乱序导致的进度回退
  • 补充了副作用依赖,外部传入的订单状态变化时会自动同步内部进度
  • 对延迟时间做了兜底处理,订单创建时间过久时也不会出现异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 01:45:02