Функция javascript canvas не работает без предупреждения

Я делаю некоторые демонстрационные веб-страницы в рамках портфеля, чтобы показать потенциальных работодателей. Одна страница - это симуляция плазменной дуги в "плазменном шаре", которая затем поворачивается для просмотра "дуги" на 360 градусов.
Повторное редактирование дуги через каждое из вращений ТОЛЬКО работает, если я поместил "предупреждение" после каждого перерисовки и затем отменил оповещения при запуске script. Без предупреждения ничего не происходит.

Есть ли у кого-нибудь объяснение/решение? Здесь функция перерисовки:

function reDraw(yAngle) //work in progress - redraw the arc through 360 degrees to see the path
{
   var xCs;
   var yCs;

   for(degrees=10; degrees<360; degrees+=1)//spin sphere through 360 degrees
   {   

      context1 = document.getElementById("canvas1").getContext("2d");

      context1.clearRect(0,0,600,600);

      radialGrad(1,'canvas1',300,300,300,300,300,0,0,1,colour1,colour2,0,0,600,600);

      firstMove=true;

      for(moves=0; moves<axisMove; moves++)
      {
         if(firstMove)//start at centre of sphere for each re-draw
         {
            xCs=300;
            yCs=300;
            firstMove=false;         
         }

         context1.beginPath();

         context1.moveTo(xCs,yCs);         

         spinAngle=(degrees/180*Math.PI);

         //we are spinning in the X-Z plane so resolve X-Z moves only - retrieve each positive or negative move from the axis move arrays

         xCs=xCs+(zCStep[moves]*Math.sin(spinAngle))+(xCStep[moves]*Math.cos(spinAngle));

         yCs=yCs+yCStep[moves];

         context1.lineTo(xCs,yCs);

         context1.shadowBlur=2;
         context1.shadowColor="grey";

         context1.strokeStyle="white";
         context1.stroke();

      }
      alert();   
   }

}

Ответ 1

Благодаря своей (исторически) однопоточной природе, Webbrowsers повторно рисуют контент, когда заканчивается (javascript) функция (обработчик) (та же проблема с индикаторами выполнения, ajax-load gif и т.д.).
Таким образом, даже если одна итерация вашего цикла займет полтора секунды (в результате получается 1FPS), холст все равно не будет перерисовываться (то же самое относится к остальной части содержимого страницы), пока ваш javascript не закончится.

Небольшая заметка: одним из самых больших преимуществ веб-работников HTML5 является то, что они запускаются в своем потоке, поэтому они не блокируют браузер.

Общим решением (по историческим причинам) является использование таймера (setInterval кажется лучшим для вашего конкретного случая или setTimeout), чтобы браузер перерисовал контент (в этом случае холст- элемент).

EDIT:
Стефано Ортиси напомнил мне в своем комментарии ниже requestAnimationFrame и дал отличную ссылку: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
В основном это основная причина существования, поэтому нам не нужно использовать одни и те же таймеры, имея оптимизированную для браузера реализацию (против таймеров) и в идеале использовать ее вместе с веб-мастерами (yay, extra thread).

Сначала этот API был довольно "живой" спецификацией (именно поэтому я и забыл об этом), но на данный момент пыль, похоже, достаточно уладила, чтобы создать приятный polyfill (см. ссылку выше).
Я согласен, что anno dec. 2013 это лучшее решение, определяющее ваш собственный таймер, так как "если вы запустили цикл анимации на невидимой вкладке, браузер не будет работать, что означает меньше использования процессора, графического процессора и памяти, что приведет к значительно более длительной батарее жизнь".

Ответ 2

По своему определению элемент <canvas> использует битмарт-буфер. Вы можете думать о <canvas> как <img> с изменяемым растровым изображением.

Script рисует это растровое изображение (но не на экране). И браузер делает это растровое изображение, когда у него есть шанс.

Чтобы дать браузеру возможность нарисовать растровое изображение на каком-то этапе, вы должны каким-то образом выполнить выполнение из вашего script в браузере: вызовите alert(), setTimeout/Interval или сделайте рисунок в кадрах анимации (requestAnimationFrame).

requestAnimationFrame - это в значительной степени запрос перерисовать вид браузера, который будет происходить после следующих 16 мс (максимум 60 кадров в секунду в браузерах) или около того.