理解画布中的Javascript异步setInterval

时间:2015-03-20 19:13:54

标签: javascript canvas asynchronous synchronous

以下代码使用init()调用setInterval方法时,会在中心创建一个球。当keydown()事件被触发时,球在X和Y轴上移动(取决于用户按下的键)。我很难理解的是按下按键时会发生什么。

当按下某个键以更新键值(setIntervalkeyLeft等)时,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>

3 个答案:

答案 0 :(得分:4)

Javascript(在浏览器中)是一种事件驱动的语言。大多数时候,没有任何东西被执行。当事件发生且脚本已为该特定类型的事件注册了侦听器时,该事件将被放入队列中。如果当前正在执行脚本的某些部分,它将不会被中断 - 相反,当它完成时,浏览器将从队列中提取下一个事件并开始为其执行注册的处理程序。

在您的代码中,您正在注册两种事件:计时器事件(隐式地,使用setInterval)和keydown事件(显式地,使用jQuery,它使用addEventListener)。触发计时器事件时,将执行Ball.draw方法。如果keydown事件在运行时到达,它将在队列中等待Ball.draw完成。然后将它分派给您指定的处理函数。反之亦然:如果keydown处理程序正在进行,10毫秒通过,并且发生计时器事件,则计时器事件必须等到keydown处理程序完成。这就是为什么Javascript计时器本质上不精确的一个原因。

简短版:您的keydown处理程序可以在Ball.draw的执行之间执行。在Ball.draw下次调用时,它对两个函数使用的变量所做的任何更改都将可见。

答案 1 :(得分:2)

setInterval方法调度事件以供将来执行,但在时间结束并且调用该方法之前不会阻塞。 JS将在方法调用期间阻塞,并在完成时停止阻塞。

编写此代码的方式,每隔10ms将调用draw方法(这比浏览器甚至可以渲染的速度快60 fps或〜每16ms)。如果自上次调用后发生了keydown事件,则draw方法将获取新的布尔值/设置并采取适当的操作。

有关时间的更多信息,请参阅notes section on MDN

答案 2 :(得分:1)

JavaScript是单线程的,所以即使你有一个多处理器设备,javascript代码也会在该单个线程上执行。

setInterval以“异步”方式运行,但是...... 异步并不意味着代码在单独的线程或处理器上运行。这意味着您的同步代码和异步代码在队列中发出时间片。并且只有一个且只有一个线程正在为该队列中的所有切片提供服务。

您的setInterval将尝试执行每个#ms但它将被其他操作阻止,并且只会在唯一线程可用时执行。因此setInterval无法保证以指定的时间间隔执行。

触发键(或鼠标)事件时,该事件将被放入队列,但不会调用键事件处理程序。该关键事件处理程序将在其原始事件发生在队列中时运行。