2015-03-20 3 views
1

Следующий код создает холст с шаром в центре, когда вызывается метод init(), используя setInterval. Когда происходит событие keydown(), шар перемещается по осям X и Y (в зависимости от того, какую клавишу нажал пользователь). Я пытаюсь понять, что происходит, когда нажата клавиша.Понимание Javascript asynchronous setInterval in canvas

Имеет ли setInterval остановку, когда клавиша нажата, чтобы обновить значение ключа (keyLeft, keyRight и т.д.), а затем возобновляется и принимает обновленные значения во внимание

ИЛИ

ли код внутри ключевое событие выполняется, пока выполняется setInterval?

Я читал, что setInterval является асинхронным, а ключевые события синхронны, и поскольку Javascript является одиночным, второй вариант не может быть правдой, верно? Я мог бы действительно использовать ваши знания по этому вопросу.

<canvas id="canvas" style="border: 1px solid black" width="400" height="400"></canvas> 
    <script type="text/javascript" src="jquery.js"></script> 
    <script type="text/javascript"> 
     var Ball = { 
      positionX: 200, 
      positionY: 200, 
      keyLeft: false, 
      keyRight: false, 
      keyUp: false, 
      keyDown: false, 
      init: function() { 
       this.canvas = document.getElementById('canvas'); 
       this.ctx = this.canvas.getContext('2d'); 
       setInterval(Ball.draw, 10); 
      }, 
      circle: function (x, y, fill) { 
       this.ctx.beginPath(); 
       this.ctx.arc(x, y, 20, 0, Math.PI * 2, false); 
       if (fill) { 
        this.ctx.fill(); 
       } else { 
        this.ctx.stroke(); 
       } 
      }, 
      draw: function() { 
       Ball.ctx.clearRect(0, 0, 400, 400); 
       if (Ball.keyLeft) Ball.positionX -= 5; 
       else if (Ball.keyRight) Ball.positionX += 5; 
       if (Ball.keyUp) Ball.positionY -= 5; 
       else if (Ball.keyDown) Ball.positionY += 5; 
       Ball.circle(Ball.positionX, Ball.positionY, true); 
      } 
     } 
     Ball.init(); 

     $('body').keydown(function (e) { 
      var key = e.keyCode; 
      if (key == 37) { 
       Ball.keyLeft = true; 
      } else if (key == 39) { 
       Ball.keyRight = true; 
      } 

      if (key == 38) { 
       Ball.keyUp = true; 
      } else if (key == 40) { 
       Ball.keyDown = true; 
      } 
     }); 
    </script> 
+0

'e.which' является более удобным для браузера, просто говоря. –

ответ

3

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

В коде, вы регистрируетесь для двух видов событий: события таймера (неявно, используя setInterval) и keydown событий (явно, с помощью JQuery, которая использует addEventListener). Когда срабатывает событие таймера, выполняется ваш метод Ball.draw. Если при запуске происходит событие keydown, он ждет в очереди до завершения Ball.draw. Затем он отправляется на назначенную вами функцию обработчика. И наоборот: если выполняется обработчик keydown, проходит 10 миллисекунд и происходит событие таймера, событие таймера должно ждать завершения обработчика keydown. Это одна из причин, по которой таймеры Javascript по своей сути являются неточными.

Краткая версия: ваш keydown обработчик может выполняться между исполнением Ball.draw. Любые изменения, которые он делает для переменных, используемых обеими функциями, будут видны Ball.draw при следующем вызове.

+0

Так что, когда приходит событие 'keydown', очередь будет выглядеть примерно так:' ball.draw() ',' keydown', 'ball.draw()', 'keydown',' ball.draw() ' , 'keydown', поскольку он в основном называется постоянно, пока он поддерживается. С другой стороны, если событие 'keyup' будет введено позже, очередь будет выглядеть как' ball.draw() ',' keydown', 'ball.draw()', 'keyup',' ball.draw() ' , 'ball.draw()', 'ball.draw()', правильно? Кстати, спасибо за удивительное объяснение! :) – kidA

+0

Добро пожаловать. Очередь заказа, которую вы описываете, является одним из многих возможных упорядочений. Никогда не следует делать предположения о том, как события будут чередоваться. Конечно, браузер гарантирует определенные ограничения на связанные события (например, keydown всегда будет предшествовать клавиатуре). – radiaph

+0

Это здорово! Еще раз большое спасибо! – kidA

2

Метод setInterval планирует событие для будущего выполнения, но не блокируется до истечения времени, и метод вызывается. JS будет блокировать на протяжении всего времени вызова метода и блокировать блокировку после его завершения.

Способ, которым записывается этот код, каждые 10 месяцев будет вызываться метод рисования (который быстрее, чем браузер может даже отображать 60 кадров в секунду или каждые 16 мс). Если с момента его последнего вызова произошло событие keydown, метод draw будет выбирать этот новый boolean/setting и действовать соответствующим образом.

notes section on MDN Смотрите для получения дополнительной информации о время

1

JavaScript является однопоточным, так что даже если у вас есть многопроцессорное устройство с Javascript код будут выполняться на этом одном потоке.

setInterval работает «асинхронно», но ... асинхронно не означает, что код запускается в отдельном потоке или процессоре. Это означает, что ваш синхронный код и ваш асинхронный код выдаются в очередь в очереди. И поток один-единственный-один последовательно обслуживает все срезы в этой очереди.

Ваш setInterval будет пытаться выполнить каждый # мс, но он будет заблокирован другими операциями и будет выполняться только тогда, когда один-и-только поток доступен. Таким образом, setInterval не может быть выполнен с заданным интервалом.

Когда событие ключа (или мышки) запускается,, что событие помещается в очередь, но обработчик события ключа не вызывается. Этот обработчик ключевых событий будет запускаться, когда очередь очереди происходящего появится в очереди.