在事件监听器调用函数后,代码的执行在哪里继续?

时间:2016-03-12 20:50:45

标签: javascript function event-listener

编辑:我为任何困惑道歉。在我的代码中,循环在脚本中无限期地运行,直到达到某个条件。我的问题是,如果一个事件监听器在这个循环运行时调用一个函数,那么在函数完成之后,执行会在哪里继续?

嗯,我猜,这几乎是不言自明的。在事件监听器调用函数之后,在函数完成后代码的执行在哪里继续?

1 个答案:

答案 0 :(得分:4)

有一个事件队列,该队列中的下一个内容将被执行。例如,它可以是鼠标点击事件,窗口调整大小或超时。如果队列中没有任何内容,则运行JavaScript的容器将循环,直到队列中有东西要处理。

您可以在MDN关于"Concurrency model and Event Loop"的文章中阅读更多内容:

  

JavaScript运行时包含一个消息队列,它是要处理的消息列表。每个消息都与一个函数相关联。当堆栈为空时,将从队列中取出一条消息并进行处理。处理包括调用相关函数(从而创建初始堆栈帧)。当堆栈再次变空时,消息处理结束。

在邮件队列中添加内容的常用方法是调用

setTimeout(myfunction, 0);

当第二个参数的延迟为0时,一旦当前正在执行的代码完成,将调用函数 myfunction ,即调用堆栈变空。但请注意,可能是某些其他事件已经在队列中。在那种情况下,这些仍将首先执行。

持久循环是什么?

您在问题中添加了以下内容:

  

在我的代码中,循环在脚本中无限期地运行,直到达到某个条件。我的问题是,如果一个事件监听器在这个循环运行时调用一个函数,那么在函数完成之后,执行会在哪里继续?

如果你的循环没有通过异步调用运行(例如重复调用setTimeoutsetInterval),但看起来像这样:

while (!endingCondition) {
    // do nothing
}

然后无法调用另一个(JavaScript)事件侦听器。这样的事件将在消息队列中等待。只有当你的当前循环和它之后的任何代码完成时,才会处理该事件并导致事件监听器的调用。

让我们看看下面的例子:

var clicked = false;

document.onclick = function() {
    clicked = true;
}

while (!clicked) {};

alert('clicked!');

这里可能希望while循环被点击中断并显示警告,但事实并非如此。 click事件将在操作系统的消息队列中,但不会被JavaScript使用,因为它始终首先完成当前正在执行的代码。如上述article on MDN中所述:

  

每当函数运行时,它都不能被抢占,并且会在任何其他代码运行之前完全运行。

任何代码都包含所有JavaScript代码,包括事件处理程序中的代码。

如何编写“可中断”代码

上面的例子可以像这样工作:

var clicked = false;

document.onclick = function() {
    clicked = true;
}

function detectClick() {
    if (!clicked) {
        setTimeout(detectClick, 0); // keep repeating
        return;
    }
    alert('clicked!');
    // do something more ...
};
detectClick(); // call for first time
// We get here immediately. Code will end, and events will be processed.
// One of those "events" is a time-out, to which we have set a handler: detectClick.
// At some point a click event will be there as well, triggering the other handler.