Как сделать паузу и вызвать функцию внутри вложенного цикла for? - PullRequest
0 голосов
/ 11 июня 2019

Я пытаюсь помочь студенту, который хочет отобразить сортировку массива случайно сгенерированных цветов на веб-странице. У него есть функция, которая заполняет глобальный массив случайно сгенерированными цветами 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 серию тонких вертикальных прямоугольников цветов в массиве слева направо:

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 () через определенные промежутки времени, чтобы алгоритм сортировки отображал процесс?

Я смотрел на многих дискуссионных форумах, которые предлагают асинхронные и рекурсивные решения (которые я могу только понять), но они, кажется, никогда не применяются к вложенным циклам. Есть мысли?

1 Ответ

2 голосов
/ 11 июня 2019

Самый простой способ - сделать функции async (вещь ES2017, которую вы можете перенести, если вам нужно ориентироваться на более старые среды). Затем вы можете await задержка, которая позволяет браузеру перекрашивать холст. Использование функции async позволяет вам записывать циклы, а не асинхронные обратные вызовы, при этом сохраняя асинхронное поведение, необходимое для отображения вещей на холсте.

Вот более простой пример:

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>

Код в вопросе становится жертвой того, что я называю (в моем маленьком анемичном блоге) Ужас неявных глобалов . Ваш ученик должен объявить эти счетчики циклов.

...