您有重叠的 setTimeout 计时器,并且其中有 很多 计时器正在安排中。您只想在要显示更改时返回给浏览器,并且只想显示给定的更改一次。
由于您使用的是 ES2015+,我可能会使用生成器函数进行排序,当发生变化时产生:
function *sortGen() {
for (let i = 0; i < len; ++i) {
for (let j = 0; j < len; ++j) {
if (k[j] > k[j + 1]) {
let tmp = k[j];
k[j] = k[j + 1];
k[j + 1] = tmp;
yield j; // *** Yield to caller, saying what changed
}
}
}
}
然后调用它的代码将调用它的next 方法,进行更新,然后通过requestAnimationFrame 在下一个动画帧之前安排回调(除非你想人为地减慢它,在这种情况下@987654327 @很好)。如果浏览器不忙于做其他事情,动画帧每秒发生 60 次(大约每 16.666667 毫秒)。这是bubble 使用上面sortGen 函数的生成器:
function bubble() {
const gen = sortGen();
tick();
function tick() {
const result = gen.next();
if (!result.done) {
// *** No need to recreate all the elements, just reorder the ones that got swapped
const el = cont.children[result.value];
const next = el.nextElementSibling;
el.parentElement.insertBefore(next, el);
requestAnimationFrame(tick);
}
}
}
(您可以将其设为异步生成器并使用 for-await-of 循环,但我认为它对您的帮助并不大。)
这是一个活生生的例子;我还在代码中包含了一些 cmets,提出了其他建议:
"use strict"; // *** Use strict mode
// *** Declare your variables (the old code relied on The Horror of Implicit Globals, which
// strict mode fixes)
let k = []; // *** Consistently use semicolons (or consistently rely on ASI)
let len = 100;
let time = true;
const cont = document.getElementsByClassName("cont")[0];
// *** Don't duplicate code, just use `reset`
reset();
function reset(){
k = [];
// *** Never use += on `innerHTML`
let html = "";
for (let i = 0; i < len; i++) {
// *** Declare your variables
const t = Math.round(Math.random() * 800 ) + 5;
k.push(t);
html += makeBlock(t);
}
cont.innerHTML = html;
}
function makeBlock(value) {
return "<div class='block' style = 'height:" + value + "px'></div>";
}
function *sortGen() {
for (let i = 0; i < len; ++i) {
for (let j = 0; j < len; ++j) {
if (k[j] > k[j + 1]) {
let tmp = k[j];
k[j] = k[j + 1];
k[j + 1] = tmp;
yield j; // *** Yield to caller, saying what changed
}
}
}
}
function bubble() {
const gen = sortGen();
tick();
function tick() {
const result = gen.next();
if (!result.done) {
// *** No need to recreate all the elements, just reorder the ones that got swapped
const el = cont.children[result.value];
const next = el.nextElementSibling;
el.parentElement.insertBefore(next, el);
requestAnimationFrame(tick);
}
}
}
.cont {
width: 100%;
height: 900px;
display: block;
background-color: pink;
padding: 0px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-line-pack: center;
align-content: center;
} /* *** Don't hide closing } at the end of a line */
.cont .block {
display: inline-block;
width: 10px;
margin: auto 1px;
background-color: red;
font-size: 5px;
bottom: 0px;
} /* *** Don't hide closing } at the end of a line */
<button class="reset" onclick="reset()">Reset Array
</button>
<button class="bubble" onclick="bubble()">Bubble Sort
</button>
<div class="cont">
</div>
Also on CodePen.
对于它的价值,异步生成器方法看起来像这样:
const nextFrame = cb => new Promise(resolve => {
requestAnimationFrame(() => {
cb();
resolve();
});
});
function bubble() {
(async () => {
for await (const value of sortGen()) {
await nextFrame(() => {
const el = cont.children[value];
const next = el.nextElementSibling;
el.parentElement.insertBefore(next, el);
});
}
})()
.catch(error => {
// Handle/report error here...
console.error(error);
});
}
"use strict"; // *** Use strict mode
// *** Declare your variables (the old code relied on The Horror of Implicit Globals, which
// strict mode fixes)
let k = []; // *** Consistently use semicolons (or consistently rely on ASI)
let len = 100;
let time = true;
const cont = document.getElementsByClassName("cont")[0];
// *** Don't duplicate code, just use `reset`
reset();
function reset(){
k = [];
// *** Never use += on `innerHTML`
let html = "";
for (let i = 0; i < len; i++) {
// *** Declare your variables
const t = Math.round(Math.random() * 800 ) + 5;
k.push(t);
html += makeBlock(t);
}
cont.innerHTML = html;
}
function makeBlock(value) {
return "<div class='block' style = 'height:" + value + "px'></div>";
}
function *sortGen() {
for (let i = 0; i < len; ++i) {
for (let j = 0; j < len; ++j) {
if (k[j] > k[j + 1]) {
let tmp = k[j];
k[j] = k[j + 1];
k[j + 1] = tmp;
yield j; // *** Yield to caller, saying what changed
}
}
}
}
const nextFrame = cb => new Promise(resolve => {
requestAnimationFrame(() => {
cb();
resolve();
});
});
function bubble() {
(async () => {
for await (const value of sortGen()) {
await nextFrame(() => {
const el = cont.children[value];
const next = el.nextElementSibling;
el.parentElement.insertBefore(next, el);
});
}
})()
.catch(error => {
// Handle/report error here...
console.error(error);
});
}
.cont {
width: 100%;
height: 900px;
display: block;
background-color: pink;
padding: 0px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-line-pack: center;
align-content: center;
} /* *** Don't hide closing } at the end of a line */
.cont .block {
display: inline-block;
width: 10px;
margin: auto 1px;
background-color: red;
font-size: 5px;
bottom: 0px;
} /* *** Don't hide closing } at the end of a line */
<button class="reset" onclick="reset()">Reset Array
</button>
<button class="bubble" onclick="bubble()">Bubble Sort
</button>
<div class="cont">
</div>
Also on CodePen.