async await实现归并排序可视化时绘制停顿失效该如何解决
原代码停顿失效的核心原因
你当前的归并排序逻辑是同步递归执行的,async/await只会暂停当前async函数的执行流,不会阻塞外层同步代码:
- 普通函数调用async函数时不会自动等待,
merger里调用mergeDraw没有加await,会直接返回继续执行后续合并逻辑 - 所有合并操作会在几毫秒内全部跑完,所有绘制任务同步触发,自然看不到分步停顿的效果
更适合可视化的实现方案:任务队列+定时调度
这个方案不需要修改归并排序的核心逻辑,把排序计算和渲染完全分离,稳定性更高,调整节奏也更简单。
实现步骤
- 先定义全局的绘制任务队列和动画间隔配置
// 存储所有合并步骤的绘制任务 const drawQueue = []; // 两次绘制的停顿时间,单位ms,可根据需求调整 const DRAW_INTERVAL = 100;
- 修改
merger函数,将绘制逻辑改成收集任务
注意要深拷贝数组,避免后续排序操作修改数组引用,导致所有绘制任务都用最终排序完成的数组
function merger(arr1, arr2) { let i = 0,j = 0,mergedArr = []; while (i < arr1.length && j < arr2.length) { if (arr1[i][0] > arr2[j][0]){ mergedArr.push(arr2[j]); j++; } else{ mergedArr.push(arr1[i]); i++; } } while (i < arr1.length) { mergedArr.push(arr1[i]); i++; } while (j < arr2.length) { mergedArr.push(arr2[j]); j++; } var lowest = mergedArr[0][1]; for( num = 1; num < mergedArr.length; num++){ if(mergedArr[num][1] < lowest){ lowest = mergedArr[num][1]; } } // 原mergeDraw调用改为推入任务队列,深拷贝数组 drawQueue.push({ data: JSON.parse(JSON.stringify(mergedArr)), startPoint: lowest }); return mergedArr; }
- 剥离
mergeDraw的异步逻辑,只保留纯绘制功能
function mergeDraw(anArray,startPoint){ var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); // 按需添加清屏逻辑,不需要保留历史绘制轨迹就保留这行 ctx.clearRect(0, 0, c.width, c.height); let j = startPoint; for(let num = 0; num < anArray.length; num++){ anArray[num][1] = j; ctx.lineWidth = 3.2 ; ctx.strokeStyle = 'seagreen' ctx.beginPath(); ctx.moveTo(j, 0); ctx.lineTo(j, 800); ctx.stroke(); ctx.lineWidth = 3; ctx.strokeStyle = 'black' ctx.beginPath(); ctx.moveTo(j, 0); ctx.lineTo(j, anArray[num][0]); ctx.stroke(); j+=8; } }
- 编写动画调度函数,按顺序执行队列里的绘制任务
function startAnimation() { // 队列空就结束动画 if(drawQueue.length === 0) return; // 取出第一个任务执行绘制 const task = drawQueue.shift(); mergeDraw(task.data, task.startPoint); // 停顿指定时间后执行下一个任务 setTimeout(startAnimation, DRAW_INTERVAL); }
- 触发排序和动画的逻辑调整
// 先执行完整的归并排序,生成所有绘制任务 mergeSort(你的待排序原始数组); // 再启动逐帧动画 startAnimation();
内容的提问来源于stack exchange,提问作者Kenneth Lamar Cole
相关产品推荐
相关产品推荐

