为什么setTimeout没有取消我的循环?

时间:2014-02-09 08:04:38

标签: javascript infinite-loop single-threaded

我想知道JavaScript while语句(在Chrome的控制台中)可以在几毫秒内递增一个变量多少次,所以我很快将这个片段直接写入控制台:

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }

问题在于它永远存在 为什么会发生这种情况,我该如何解决?

6 个答案:

答案 0 :(得分:80)

这又回到了JavaScript 1 的单线程特性。发生的事情就是这样:

  1. 您的变量已分配。
  2. 您安排了一项功能,以设置run = false。计划在运行当前函数后运行(或其他任何当前活动的函数)。
  3. 你有无限循环并留在当前功能中。
  4. 在无限循环(从不)之后,setTimeout()回调将被执行并run=false
  5. 正如您所看到的,setTimeout()方法在这里不起作用。您可以通过检查while条件下的时间来解决这个问题,但这会篡改您的实际测量值。

    1 至少出于更实际的目的,您可以将其视为单线程。实际上有一个所谓的“事件循环”。在该循环中,所有函数都会排队,直到它们被执行。如果排队一个新函数,它将被放在该队列中的相应位置。 当前函数完成后,引擎从队列中获取下一个函数(关于引入的时序,例如setTimeout()并执行它。
    因此,在每个时间点只执行一个函数,从而使执行几乎是单线程的。事件有一些例外情况,将在下面的链接中讨论。


    供参考:

答案 1 :(得分:24)

JavaScript是单线程的,所以当你在循环中时,没有其他任何东西被执行。

答案 2 :(得分:19)

要保持Chrome的真实速度而不必经常检索计算速度的时间,您可以尝试使用此JS代码:

var start = new Date().getTime()
var i = 0
while(i<1000000)
{
    i++
}
var end = new Date().getTime()
var delta = end-start
var speed = i/delta
console.log(speed + " loops per millisecond")

答案 3 :(得分:4)

Javascript是单线程的,这意味着它一次只运行一条指令。

事件系统与许多其他语言和库一样,由事件循环处理。事件循环基本上是一个循环,在每次迭代时检查队列中的消息和调度事件。

在javascript中(如实现此模式的语言),当堆栈为空时调用事件循环,也就是说,当所有函数都返回时,换句话说,在程序代码的末尾。

你的“真实”程序在幕后看起来像这样:

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }

while(true) {
/*
 * check for new messages in the queue and dispatch
 * events if there are some
 */
  processEvents();
}

所以来自时钟的超时结束的消息永远不会被处理。

有关事件循环的更多信息: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop


当然它有点复杂,请在这里查看这些示例:Is JavaScript guaranteed to be single-threaded? tl; dr:在某些浏览器引擎中,某些外部事件不依赖于事件循环和当它们发生时立即被触发,抢占当前任务。但是setTimeout不是这种情况,它只是向队列添加消息而不会立即触发。)

答案 4 :(得分:2)

While循环不访问setTimeout。你有代码设置运行true,然后它永远不会变成错误。

答案 5 :(得分:1)

JavaScript有单线程,并且在任何地方都有单线程。

我认为这个问题很好: Is JavaScript guaranteed to be single-threaded?

当你的代码在循环中时,其他ocde不执行并阻塞。