编辑:我为任何困惑道歉。在我的代码中,循环在脚本中无限期地运行,直到达到某个条件。我的问题是,如果一个事件监听器在这个循环运行时调用一个函数,那么在函数完成之后,执行会在哪里继续?
嗯,我猜,这几乎是不言自明的。在事件监听器调用函数之后,在函数完成后代码的执行在哪里继续?
答案 0 :(得分:4)
有一个事件队列,该队列中的下一个内容将被执行。例如,它可以是鼠标点击事件,窗口调整大小或超时。如果队列中没有任何内容,则运行JavaScript的容器将循环,直到队列中有东西要处理。
您可以在MDN关于"Concurrency model and Event Loop"的文章中阅读更多内容:
JavaScript运行时包含一个消息队列,它是要处理的消息列表。每个消息都与一个函数相关联。当堆栈为空时,将从队列中取出一条消息并进行处理。处理包括调用相关函数(从而创建初始堆栈帧)。当堆栈再次变空时,消息处理结束。
在邮件队列中添加内容的常用方法是调用
setTimeout(myfunction, 0);
当第二个参数的延迟为0时,一旦当前正在执行的代码完成,将调用函数 myfunction ,即调用堆栈变空。但请注意,可能是某些其他事件已经在队列中。在那种情况下,这些仍将首先执行。
您在问题中添加了以下内容:
在我的代码中,循环在脚本中无限期地运行,直到达到某个条件。我的问题是,如果一个事件监听器在这个循环运行时调用一个函数,那么在函数完成之后,执行会在哪里继续?
如果你的循环没有通过异步调用运行(例如重复调用setTimeout
或setInterval
),但看起来像这样:
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.