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

React归并排序可视化:实时调整setTimeout延迟实现动态调速

解决React归并排序可视化实时调速问题

核心问题分析

你当前用for循环一次性调度所有setTimeout,延迟值在循环执行时就已固定,无法响应滑块实时修改的速度值。要实现实时调速,必须改成逐帧调度——执行完当前动画帧后,再根据最新的速度值计算下一次的延迟,然后执行下一帧。

解决方案代码示例

首先封装一个通用的延迟函数,配合async/await实现顺序执行:

// 封装延迟函数,返回Promise
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

修改排序执行逻辑,改成异步逐帧执行:

const MergeSort = () => {
  const [speed, setSpeed] = useState(10); // 滑块绑定的速度state,值越大动画越快

  const runMergeSort = async () => {
    const animations = sortingAlgorithms.mergeSort(array);
    const topArrayBars = document.getElementsByClassName("array__bar");
    const bottomArrayBars = document.getElementsByClassName("array__baraux");

    for (let i = 0; i < animations.length; i++) {
      const animation = animations[i];
      
      // 执行当前帧的动画逻辑(和你原代码逻辑一致)
      if (animation.type === "look") {
        for (let j = 0; j < topArrayBars.length; j++) {
          topArrayBars[j].style.backgroundColor = "rgb(57, 200, 195)";
        }
        for (let j = animation.look[0]; j <= animation.look[1]; j++) {
          topArrayBars[j].style.backgroundColor = "rgb(255, 79, 120)";
        }
      } else if (animation.type === "join") {
        for (let j = 0; j < topArrayBars.length; j++) {
          topArrayBars[j].style.backgroundColor = "rgb(57, 200, 195)";
        }
        for (let j = animation.leftIndices[0]; j <= animation.leftIndices[1]; j++) {
          topArrayBars[j].style.backgroundColor = "rgb(255, 77, 252)";
        }
        for (let j = animation.rightIndices[0]; j <= animation.rightIndices[1]; j++) {
          topArrayBars[j].style.backgroundColor = "rgb(255, 237, 77)";
        }
      } else if (animation.type === "place") {
        bottomArrayBars[animation.newIdx].style.height = topArrayBars[animation.oldIdx].style.height;
        bottomArrayBars[animation.newIdx].style.backgroundColor = topArrayBars[animation.oldIdx].style.backgroundColor;
        topArrayBars[animation.oldIdx].style.backgroundColor = "rgba(57, 200, 195, 0)";
      } else if (animation.type === "lift") {
        for (let j = animation.range[0]; j <= animation.range[1]; j++) {
          topArrayBars[j].style.height = `${animation.newVals[j - animation.range[0]]}px`;
          topArrayBars[j].style.backgroundColor = "rgb(57, 200, 195)";
        }
        for (let j = 0; j < topArrayBars.length; j++) {
          topArrayBars[j].style.backgroundColor = "rgb(57, 200, 195)";
        }
        for (let j = 0; j < bottomArrayBars.length; j++) {
          bottomArrayBars[j].style.backgroundColor = "rgba(57, 200, 195, 0)";
        }
      }

      // 根据当前最新speed计算延迟,这里speed越大延迟越小(速度越快)
      // 可根据需求调整计算逻辑,比如speed范围1-20对应1000ms到50ms
      const currentDelay = 1000 / speed;
      // 等待延迟后执行下一帧
      await delay(currentDelay);
    }
  };

  return (
    <>
      {/* 速度控制滑块 */}
      <input
        type="range"
        min="1"
        max="20"
        value={speed}
        onChange={(e) => setSpeed(Number(e.target.value))}
      />
      {/* 触发排序的按钮 */}
      <button onClick={runMergeSort}>开始归并排序</button>
      {/* 数组可视化的DOM结构 */}
    </>
  );
};

关键改进点

  • 用async/await替代一次性setTimeout调度,每帧执行完毕后才计算下一次的延迟,确保每次都取最新的滑块速度值。
  • 延迟计算逻辑可灵活调整,比如如果你的speed代表“每秒执行的帧数”,那延迟就是1000 / speed;如果speed是毫秒数,直接用speed即可。
  • 额外建议:尽量避免直接操作DOM,把数组条的样式(颜色、高度)存入React state,通过组件渲染更新样式,更符合React的数据流规范,减少潜在的DOM操作问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:50:34