简体   繁体   English

为什么 setTimeout 不取消我的循环?

[英]Why isn't setTimeout cancelling my loop?

I wondered how many times can a JavaScript while statement (in Chrome's console) can increment a variable in a millisecond, so I quickly wrote this snippet directly into console:我想知道一个 JavaScript 的while语句(在 Chrome 的控制台中)可以在一毫秒内增加一个变量多少次,所以我很快就把这个片段直接写到了控制台中:

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

The problem is that it runs forever.问题是它永远运行。
Why is this happening, and how can I solve it?为什么会发生这种情况,我该如何解决?

This comes back to the one-threaded nature of JavaScript 1 .这又回到了 JavaScript 1的单线程特性。 What happens is pretty much this:发生的事情几乎是这样的:

  1. Your variables are assigned.您的变量已分配。
  2. You schedule a function, to set run = false .您安排了一个函数,以设置run = false This is scheduled to be run after the current function is run (or whatever else is currently active).该计划目前的功能是运行(或任何其他当前活动)运行。
  3. You have your endless loop and stay inside the current function.你有你的无限循环并留在当前函数中。
  4. After your endless loop ( never ), the setTimeout() callback will be executed and run=false .在你的无限循环( never )之后, setTimeout()回调将被执行并且run=false

As you can see, a setTimeout() approach wont work here.如您所见, setTimeout()方法在这里不起作用。 You might work around that by checking the time in the while condition, but this will tamper with your actual measurement.您可以通过检查while条件中的时间来解决这个问题,但这会干扰您的实际测量。

1 At least for more practical purposes you can see it as single-threaded. 1至少出于更实际的目的,您可以将其视为单线程。 Actually there is an so called "event-loop".实际上有一个所谓的“事件循环”。 In that loop all functions get queued until they are executed.在该循环中,所有函数都会排队,直到它们被执行。 If you queue up a new function, it is put at the respective position inside that queue.如果您排队一个新函数,它会被放置在该队列中的相应位置。 After the current function has finished, the engine takes the next function from the queue (with respect to timings as introduced, eg, by setTimeout() and executes it.当前功能完成之后,发动机将在下次函数从队列(相对于作为引入的定时,例如,通过setTimeout()并执行它。
As a result at every point in time just one function is executed, thus making the execution pretty much single threaded.结果在每个时间点只执行一个函数,从而使执行几乎是单线程的。 There are some exceptions for events, which are discussed in the link below.事件有一些例外情况,在下面的链接中进行了讨论。


For reference:以供参考:

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

To keep the true speed of Chrome without having to constantly retrieve the time to calculate speed, you could try this JS code:为了保持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")

Javascript is single-threaded, that mean it runs only one instruction at a time, sequentially. Javascript 是单线程的,这意味着它一次只按顺序运行一条指令。

The event system, like in many other languages and library, is handle by an event loop.与许多其他语言和库一样,事件系统由事件循环处理。 The event loop is basically a loop, which on each iteration check for message in the queue, and dispatch events.事件循环基本上是一个循环,它在每次迭代时检查队列中的消息,并调度事件。

In javascript (as in mot of languages implementing this pattern), the event loop is called when the stack is empty, that is to say, when all functions have returns, in other word, at the end of the program code.在 javascript 中(就像在实现这种模式的语言中一样),当堆栈为空时,即所有函数都有返回时,换句话说,在程序代码的末尾,将调用事件循环。

Your "real" program look something like this behind the scene :你的“真实”程序在幕后看起来像这样:

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();
}

So the message from the clock saying timeout is over is never processed.因此,永远不会处理来自时钟的消息说超时结束。

More info on the event loop on : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop关于事件循环的更多信息: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop


Of course it is a bit more complex, check here those examples : Is JavaScript guaranteed to be single-threaded?当然它有点复杂,请在此处查看这些示例: JavaScript 是否保证是单线程的? ( tl;dr: In some browser engines, some external events are not dependent on the event loop and are immediately fired when they occur, preempting the current task. But this is not the case with setTimeout, which just add a message to the queue and never fires immediately.) ( tl;dr:在一些浏览器引擎中,一些外部事件不依赖于事件循环,一旦发生就会立即触发,抢占当前任务。但 setTimeout 不是这种情况,它只是向队列中添加一条消息并且永远不会立即开火。)

The While loop doesn't access the setTimeout. While 循环不访问 setTimeout。 You have code that sets run true, and then it will never become false.您有设置运行为真的代码,然后它永远不会变为假。

JavaScript has single thread and has single-threaded anywhere. JavaScript 具有单线程,并且在任何地方都有单线程。

I think this question in good: Is JavaScript guaranteed to be single-threaded?我认为这个问题很好: JavaScript 是否保证是单线程的?

When your code is in loop other ocde not execute and block.当您的代码处于循环中时,其他 ocde 不会执行并阻塞。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM