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

如何让await函数延迟小于1毫秒?排序可视化工具优化需求

解决排序可视化工具高速度(每秒千次以上比较)的问题

问题根源

浏览器的setTimeout存在最小延迟限制(通常约4ms),即使设置delay为0或1ms,实际等待时间也会被浏览器强制拉高,导致无法达到每秒1000次以上的比较速度。此外,每步单独更新DOM的操作也会带来额外性能开销,进一步拖慢执行效率。

解决方案:批量处理+帧同步

当delay处于0-1ms区间时,跳过逐步骤的setTimeout,改为在每一帧(通过requestAnimationFrame)内批量执行多个排序步骤,同时批量更新DOM。这种方式既能突破浏览器的延迟限制,又能保证可视化的流畅性,轻松实现每秒千次以上的比较速度。

修改后的完整代码实现

HTML(无改动)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sorting Algorithm Visualizer</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="controls">
        <select id="algorithm">
            <option value="bubble">Bubble Sort</option>
            <option value="selection">Selection Sort</option>
            <option value="insertion">Insertion Sort</option>
            </select>
        <input type="text" id="Size" value=100>
        <button onclick="gen()">Generate</button>
        <input type="number" id="delay" min="0" value="1"> (ms delay)
    </div>
        <div class="bars" id="setup"></div>
        <script src="script.js"></script>
</body>
</html>

CSS(无改动)

.bars{
  background-color: red;
  width: 10px;
  height: 10px;
  position: absolute;
  bottom: 100%;
  margin: 0px;
  visibility: hidden;
}

JavaScript(核心修改)

var list;
var ind;
var size;
var sort;
var delay;
var count;
var height = Math.floor(window.innerHeight * 0.9);
var width = Math.floor(window.innerWidth);
// 批量处理步长,可根据设备性能调整
const BATCH_SIZE = 50;

function swap(arr, a, b) {
  [arr[a], arr[b]] = [arr[b], arr[a]];
}

// 批量更新DOM元素,减少重复操作
function batchUpdate(indices) {
  indices.forEach(item => {
    const bar = document.getElementById("bar" + item);
    if (bar) {
      bar.style.visibility = "visible";
      bar.style.height = (height / size) * list[item] + "px";
      const hue = (list[item] / size) * 360;
      bar.style.backgroundColor = `hsl(${hue}, 100%, 50%)`;
    }
  });
}

// 自定义等待函数,根据delay值选择不同策略
function sleep(ms) {
  if (ms <= 1) {
    // 低延迟时,与浏览器渲染帧同步
    return new Promise(resolve => requestAnimationFrame(resolve));
  } else {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

async function bubbleSort(arr) {
  let updatedIndices = new Set();
  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < (arr.length - i - 1); j++) {
      if (arr[j] > arr[j + 1]) {
        swap(list, j, j + 1);
        updatedIndices.add(j);
        updatedIndices.add(j + 1);
      }

      // 低延迟下批量处理+帧同步
      if (delay <= 1 && (j % BATCH_SIZE === 0 || j === arr.length - i - 2)) {
        batchUpdate(Array.from(updatedIndices));
        updatedIndices.clear();
        await sleep(delay);
      } else if (delay > 1) {
        // 正常延迟下逐步骤更新
        batchUpdate([j, j+1]);
        await sleep(delay);
      }
    }
  }
  // 最终更新所有元素确保状态正确
  batchUpdate(Array.from({length: arr.length}, (_,k) => k));
}

async function selectionSort(arr) {
  let updatedIndices = new Set();
  for (let i = 0; i < arr.length; i++) {
    let lowest = i;
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[lowest]) {
        lowest = j;
        updatedIndices.add(i);
        updatedIndices.add(lowest);
      }

      if (delay <= 1 && (j % BATCH_SIZE === 0 || j === arr.length - 1)) {
        batchUpdate(Array.from(updatedIndices));
        updatedIndices.clear();
        await sleep(delay);
      } else if (delay > 1) {
        batchUpdate([j, lowest]);
        await sleep(delay);
      }
    }
    if (lowest !== i) {
      swap(list, i, lowest);
      updatedIndices.add(i);
      updatedIndices.add(lowest);
    }
    if (delay <=1) {
      batchUpdate(Array.from(updatedIndices));
      updatedIndices.clear();
      await sleep(delay);
    } else {
      batchUpdate([i, lowest]);
      await sleep(delay);
    }
  }
  batchUpdate(Array.from({length: arr.length}, (_,k) => k));
}

function shuffle(arr) {
  ind = list.length - 1;
  for (var i = arr.length - 1; i > 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    swap(arr, i, j);
  }
}

function createBars(arr) {
  count = 0;
  while (count < arr.length) {
    var bar = document.createElement('div');
    bar.classList.add("bars");
    bar.setAttribute('id', "bar" + count);
    document.body.appendChild(bar);
    bar.style.width = Math.ceil(width / size) + "px";
    bar.style.visibility = "visible";
    bar.style.bottom = "0%";
    bar.style.left = count * width / size + "px";
    bar.style.height = (height / size) * arr[count] + "px";
    const hue = (arr[count] / size) * 360;
    bar.style.backgroundColor = `hsl(${hue}, 100%, 50%)`;
    count++;
  }
}

async function gen() {
  if (list != undefined) {
    // 移除旧的bar元素
    document.querySelectorAll('.bars').forEach(bar => bar.remove());
  }
  list = [];
  size = parseInt(document.getElementById("Size").value);
  for (count = 1; count <= size; count++) {
    list.push(count);
  }
  shuffle(list);
  createBars(list);
  await sleep(1000);
  sort = document.getElementById("algorithm").value;
  delay = parseInt(document.getElementById("delay").value);
  switch (sort) {
    case "bubble":
      await bubbleSort(list);
      break;
    case "selection":
      await selectionSort(list);
      break;
  }
}

function updateAll() {
  batchUpdate(Array.from({length: list.length}, (_,k) => k));
}

关键优化说明

  1. 批量处理:低延迟模式下,每执行BATCH_SIZE次排序步骤后再更新DOM,减少DOM操作次数
  2. 帧同步:使用requestAnimationFrame替代setTimeout,确保更新与浏览器渲染节奏一致,避免阻塞主线程
  3. 修复原代码问题:移除无效的parent元素引用,将delay转为数字类型,避免类型错误
  4. 状态跟踪:使用Set记录需要更新的元素索引,避免重复操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:37:03