如何在嵌套的 for 循环中暂停和调用函数?
How do I pause and call a function inside a nested for loop?
我正在尝试帮助一位想要在网页上显示随机生成的颜色数组排序的学生。他有一个用随机生成的 HSL 颜色填充全局数组的函数:
function shuffle(array)
{
for(i=array.length-1;i>0;i--)
{
var random = Math.floor(Math.random() * (i+1));
var temp = array[i];
array[i] = array[random];
array[random] = temp;
}
}
另一个函数在 HTML canvas 上显示数组中从左到右的一系列颜色的垂直细矩形:
function draw()
{
for(d=0;d<361;d++)
{
hue = cArray[d].slice(4,cArray[d].indexOf(",", 4));
ctx.fillStyle = `hsl(`+ hue + `,100%,50%)`;
ctx.fillRect(x,0,4,canvas.height);
x=x+3;
}
x=0; //reset x-coordinate
}
然后是一个包含冒泡排序算法的函数:
function bubbleSort(array)
{
for(i=0;i<array.length;i++)
{
for(j=1;j<array.length;j++)
{
var hue1 = array[j-1].slice(4,array[j-1].indexOf(","));
var hue2 = array[j].slice(4,array[j].indexOf(","));
if(Number(hue1) > Number(hue2))
{
var temp = array[j-1];
array[j-1] = array[j];
array[j] = temp;
// webpage hangs if function call put here
}
}
}
// webpage works if function call put here
}
如果 draw() 函数调用在嵌套循环内,网页会挂起。但如果 draw() 函数调用在循环之后,则排序完成,学生只能看到最终排序的数组。我们如何暂停循环并每隔一段时间调用draw()函数,以便排序算法显示过程?
我看过很多建议异步和递归解决方案(我只能理解)的论坛,但它们似乎从未适用于嵌套循环。有什么想法吗?
最简单的方法是创建函数 async
(一个 ES2017 的东西,如果你必须针对较旧的环境,你可以转换它)。然后,您可以 await
允许浏览器重新绘制 canvas 的延迟。使用 async
函数可以让您继续编写循环而不是异步回调,同时仍然获得在 canvas.
上显示内容所需的异步行为
这是一个更简单的例子:
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
function delay(ms) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, ms);
});
}
async function example() {
for (let i = 0; i < 4; ++i) {
outer.textContent = String(i);
outer.className = "cls" + (i % 4);
for (let j = 0; j < 4; ++j) {
inner.textContent = String(j);
inner.className = "cls" + (j % 4);
await delay(200);
}
}
}
example()
.catch(error => {
console.error(error);
});
.cls0 {
color: blue;
}
.cls1 {
color: red;
}
.cls2 {
color: green;
}
.cls3 {
color: black;
}
<div id="outer"></div>
<div id="inner"></div>
问题中的代码正在成为我所说的(在我贫血的小博客上)The Horror of Implicit Globals 的牺牲品。您的学生需要声明那些循环计数器。
我正在尝试帮助一位想要在网页上显示随机生成的颜色数组排序的学生。他有一个用随机生成的 HSL 颜色填充全局数组的函数:
function shuffle(array)
{
for(i=array.length-1;i>0;i--)
{
var random = Math.floor(Math.random() * (i+1));
var temp = array[i];
array[i] = array[random];
array[random] = temp;
}
}
另一个函数在 HTML canvas 上显示数组中从左到右的一系列颜色的垂直细矩形:
function draw()
{
for(d=0;d<361;d++)
{
hue = cArray[d].slice(4,cArray[d].indexOf(",", 4));
ctx.fillStyle = `hsl(`+ hue + `,100%,50%)`;
ctx.fillRect(x,0,4,canvas.height);
x=x+3;
}
x=0; //reset x-coordinate
}
然后是一个包含冒泡排序算法的函数:
function bubbleSort(array)
{
for(i=0;i<array.length;i++)
{
for(j=1;j<array.length;j++)
{
var hue1 = array[j-1].slice(4,array[j-1].indexOf(","));
var hue2 = array[j].slice(4,array[j].indexOf(","));
if(Number(hue1) > Number(hue2))
{
var temp = array[j-1];
array[j-1] = array[j];
array[j] = temp;
// webpage hangs if function call put here
}
}
}
// webpage works if function call put here
}
如果 draw() 函数调用在嵌套循环内,网页会挂起。但如果 draw() 函数调用在循环之后,则排序完成,学生只能看到最终排序的数组。我们如何暂停循环并每隔一段时间调用draw()函数,以便排序算法显示过程?
我看过很多建议异步和递归解决方案(我只能理解)的论坛,但它们似乎从未适用于嵌套循环。有什么想法吗?
最简单的方法是创建函数 async
(一个 ES2017 的东西,如果你必须针对较旧的环境,你可以转换它)。然后,您可以 await
允许浏览器重新绘制 canvas 的延迟。使用 async
函数可以让您继续编写循环而不是异步回调,同时仍然获得在 canvas.
这是一个更简单的例子:
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
function delay(ms) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, ms);
});
}
async function example() {
for (let i = 0; i < 4; ++i) {
outer.textContent = String(i);
outer.className = "cls" + (i % 4);
for (let j = 0; j < 4; ++j) {
inner.textContent = String(j);
inner.className = "cls" + (j % 4);
await delay(200);
}
}
}
example()
.catch(error => {
console.error(error);
});
.cls0 {
color: blue;
}
.cls1 {
color: red;
}
.cls2 {
color: green;
}
.cls3 {
color: black;
}
<div id="outer"></div>
<div id="inner"></div>
问题中的代码正在成为我所说的(在我贫血的小博客上)The Horror of Implicit Globals 的牺牲品。您的学生需要声明那些循环计数器。