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

