75

我想知道一个 JavaScript 语句(在 Chrome 的控制台中)可以在一毫秒内增加一个变量多少次while,所以我迅速将这段代码直接写到控制台中:

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

问题是它永远运行。
为什么会发生这种情况,我该如何解决?

4

6 回答 6

80

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

  1. 您的变量已分配。
  2. 您安排一个功能,设置run = false. 这计划在当前函数运行运行(或当前处于活动状态的任何其他函数)。
  3. 您有无限循环并留在当前函数中。
  4. 在你的无限循环(从不)之后,setTimeout()回调将被执行并且run=false.

如您所见,一种setTimeout()方法在这里行不通。您可以通过检查while条件中的时间来解决此问题,但这会篡改您的实际测量结果。

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


以供参考:

于 2014-02-09T08:10:35.163 回答
24

JavaScript 是单线程的,因此,当您处于循环中时,不会执行任何其他操作。

于 2014-02-09T08:11:24.627 回答
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")
于 2014-02-09T13:29:39.730 回答
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


当然它有点复杂,请查看这些示例:JavaScript 是否保证是单线程的?( tl;dr:在某些浏览器引擎中,一些外部事件不依赖于事件循环,并且在它们发生时立即触发,抢占当前任务。但是 setTimeout 不是这种情况,它只是将消息添加到队列中并且永远不会立即开火。)

于 2014-02-09T15:16:30.047 回答
2

While 循环不访问 setTimeout。您的代码设置为 true,然后它永远不会变为 false。

于 2014-02-09T20:06:28.583 回答
1

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

我认为这个问题很好: JavaScript 是否保证是单线程的?

当您的代码处于循环中时,其他 ocde 不会执行并阻塞。

于 2014-02-10T04:31:21.107 回答