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
相关产品推荐
相关产品推荐

