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

React递归函数中SetTimeout无法按设置时长执行问题排查

归并排序递归中setTimeout超时时间不生效的原因与解决方法

问题原因

你的代码核心问题在于递归过程是同步执行的,导致所有setTimeout几乎同时被添加到浏览器的事件队列中:

  • merger函数会先同步完成所有层级的递归调用(从最上层一直递归到叶子节点,再逐层返回),这个过程没有任何等待。
  • 每一层递归结束时调用的setTimeout(merge,10,l,m,r),它们的延迟时间都是相对于递归完成的时间点,而非前一个merge操作完成的时间。
  • 所有merge回调会在递归结束后约10ms左右批量执行,修改超时时间只是让所有回调整体推迟,但执行顺序和间隔完全没有变化,所以视觉上速度一致。

对比你写的选择排序:选择排序的循环是同步执行的,每个setTimeout的延迟i*50是依次递增的,所以回调会按顺序延迟触发,这是两种场景的本质区别。

解决方案

要让归并排序的merge操作按逻辑顺序延迟执行,需要给每个setTimeout设置递增的延迟时间,确保前一个操作完成后再执行下一个。这里可以用useRef来跟踪累加的延迟值(避免触发组件重渲染):

修改后的核心代码

import { useState, useRef } from "react";

function Visualiser () {
  const [array,setarray] = useState([]);
  const delayRef = useRef(0); // 用useRef跟踪延迟时间,避免重渲染
  const BASE_DELAY = 50; // 自定义每一步的延迟间隔

  // ... 其他函数(gendivs、selectsort等)保持不变 ...

  const merge = (l,m,r) => { 
    // 去掉内部的setTimeout,改用外部递增的延迟控制
    setarray((prev) => {
      const arr = [...prev]
      var n1 = m - l + 1;
      var n2 = r - m;
    
      var L = [];
      var R = [];
      
      for (let i = 0; i < n1; i++){
        L[i] = arr[l + i];
      }
    
      for (let j = 0; j < n2; j++) {
          R[j] = arr[m + 1 + j];
      }
    
      var i = 0;
      var j = 0;
      var k = l;
     
      while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        }
        else {
            arr[k] = R[j];
            j++;
        }
        k++;
      }
      while (i < n1) {
          arr[k] = L[i];
          i++;
          k++;
      }
      while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
      }
      return arr;
    })
  }

  function merger(l,r){
    if(l>=r){
        return;
    }
    var m = l + parseInt((r-l)/2);
      
    merger(l,m);
    merger(m+1,r);

    // 每次递归调用时,累加延迟时间
    delayRef.current += BASE_DELAY;
    setTimeout(merge, delayRef.current, l, m, r);
  }

  function mergeSort () {
    let l = 0;
    let r = 249;
    delayRef.current = 0; // 每次排序前重置延迟计数器
    merger(l,r);
  }

  // ... 渲染部分保持不变 ...
}

方案说明

  • useRef的作用是在组件生命周期中保存一个可变值,更新它不会触发组件重渲染,适合跟踪这种不需要渲染的状态。
  • 每次递归调用merger时,把延迟时间累加BASE_DELAY,这样每个merge操作的延迟时间依次递增,确保它们按归并排序的逻辑顺序延迟执行。
  • 去掉merge内部的setTimeout,避免双重延迟导致时间混乱。
  • 在mergeSort开头重置delayRef.current,避免多次点击排序按钮时延迟值持续累加。

内容的提问来源于stack exchange,提问作者Anurag-210

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:40:24