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

JavaScript排序算法可视化:如何让操作过程中实时显示柱状条?

问题解决方法

核心问题原因

你用的自定义sleep函数是同步阻塞式的,它会霸占JavaScript主线程,导致浏览器无法在排序过程中更新DOM。所有的柱状条创建和排序时的高度变化,都会等到整个gen()函数(包括排序)完全执行完后才一次性渲染出来,所以看不到实时变化。

具体修正方案

1. 替换同步sleep为异步版本

把原来的同步sleep改成返回Promise的异步函数,避免阻塞主线程:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

2. 改造排序函数为异步函数

用async/await让排序过程分步执行,给浏览器留出渲染时间:

async function bubbleSort(arr) {
  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < (arr.length - i - 1); j++) {
      await sleep(delay); // 等待异步延迟,释放主线程
      if (arr[j] > arr[j + 1]) {
        swap(list, j, j + 1);
      }
    }
  }
  console.log(list);
}

3. 修改gen函数为异步函数

因为要调用异步排序函数,gen()也要改成async函数,同时修复旧元素删除逻辑:

async function gen() {
  // 清除所有旧的柱状条
  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); // 等待1秒后开始排序
  sort = document.getElementById("algorithm").value;
  delay = parseInt(document.getElementById("delay").value);
  
  if (sort == "bubble") {
    await bubbleSort(list);
  }
}

4. 修复updateAll函数参数错误

原来的updateAll传错了参数,修正为:

function updateAll() {
  for (let i = 0; i < list.length; i++) {
    update(i); // update只需要索引参数,无需传list
  }
}

5. 优化createBars函数

删除多余的updateAll()调用,创建时已设置好柱状条属性:

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.round(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";
    count++;
  }
}

6. 修正CSS底部定位

原来的bottom: 100%会让柱状条跑到页面外,改成bottom: 0让柱状条从页面底部开始:

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

完整修改后的代码

JavaScript

var list;
var ind;
var size;
var sort;
var delay;
var count;
const content = document.getElementById("content");
var height = Math.floor(window.innerHeight * 0.9);
var width = Math.floor(window.innerWidth);

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

async function bubbleSort(arr) {
  for (var i = 0; i < arr.length; i++) {
    for (var j = 0; j < (arr.length - i - 1); j++) {
      await sleep(delay);
      if (arr[j] > arr[j + 1]) {
        swap(list, j, j + 1);
      }
    }
  }
  console.log(list);
}

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 update(item) {
  const bar = document.getElementById("bar" + item);
  if (bar) {
    bar.style.visibility="visible";
    bar.style.height = (height / size) * list[item] + "px";
  }
}

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.round(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";
    count++;
  }
}

async function gen() {
  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);
  
  if (sort == "bubble") {
    await bubbleSort(list);
  }
}

function sleep(milliseconds) {
  return new Promise(resolve => setTimeout(resolve, milliseconds));
}

function updateAll() {
  for (let i = 0; i < list.length; i++) {
    update(i); 
  }
}

CSS

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

HTML

<div class="controls">
    <select id="algorithm">
        <option value="bubble">Bubble Sort</option>
        <option value="selection">Selection Sort</option>
        </select>
    <input type="text" id="Size" value=10>
    <button onclick="gen()">Generate</button>
    <input type="number" id="delay" min="0" value="100"> (ms delay)
</div>
<div id="setup"></div>

原理说明

改用异步延迟后,每次await sleep(delay)都会把主线程交还给浏览器,让浏览器有时间渲染当前的DOM变化(比如柱状条高度更新),然后再继续执行排序的下一步。这样就能看到排序过程中柱状条的实时变化了。

内容的提问来源于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 20:42:31