Javascript 为什么不是';设置超时取消我的循环?

Javascript 为什么不是';设置超时取消我的循环?,javascript,infinite-loop,single-threaded,Javascript,Infinite Loop,Single Threaded,我想知道一个JavaScript语句(在Chrome的控制台中)可以在毫秒内增加变量多少次,所以我很快将这段代码直接写到控制台中: var run = true, i = 0; setTimeout(function(){ run = false; }, 1); while(run){ i++; } 问题是它会永远运行。 为什么会发生这种情况,我如何解决它?这又回到了JavaScript1的单线程特性。发生的情况大致如下: 您的变量已分配 您可以计划一个函数,以设置run=false。计划在运

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

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }
问题是它会永远运行。

为什么会发生这种情况,我如何解决它?

这又回到了JavaScript1的单线程特性。发生的情况大致如下:

  • 您的变量已分配
  • 您可以计划一个函数,以设置
    run=false
    。计划在运行当前功能(或当前激活的任何其他功能)后运行
  • 你有一个无止境的循环,并停留在当前函数中
  • 在无限循环(never)之后,将执行
    setTimeout()
    回调,并且
    run=false
  • 如您所见,
    setTimeout()
    方法在这里不起作用。您可以通过检查
    while
    条件下的时间来解决这个问题,但这会干扰您的实际测量

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


    供参考:

    • 这里更详细地解释了一个类似的场景

    • 关于何时可以将JS视为单线程以及何时不能将其视为单线程的更深入的描述


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

    要保持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")
    
    var start=new Date().getTime()
    变量i=0
    
    虽然(iJavascript是单线程的,但这意味着它一次只能按顺序运行一条指令

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

    在javascript中(与实现此模式的语言的mot一样),当堆栈为空时,即当所有函数都有返回时,即在程序代码末尾调用事件循环

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

    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();
    }
    
    因此,时钟发出的超时结束的消息永远不会被处理

    有关事件循环的更多信息,请访问:



    当然,这有点复杂,请查看以下示例:(tl;dr:在某些浏览器引擎中,某些外部事件不依赖于事件循环,它们发生时会立即触发,抢占当前任务。但setTimeout的情况并非如此,它只向队列中添加消息,从不立即触发。)While循环不访问setTimeout。您的代码将run设置为true,然后它将永远不会变为false。

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

    我认为这个问题很好:


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

    因为while循环不会让处理器的时间到达超时,所以阅读以下内容可能会很有用:为什么这个问题的投票率如此之高?@remyabel我认为这是因为它实际上是演示单线程如何工作的一个很好的例子。这是JS th的一个常见假设在某个时间间隔/超时将立即中断控制流并执行,在某些情况下(如上所述),这种情况永远不会发生。作为下面答案的扩展,这是您使用延迟递归函数执行预期操作的方式:
    var run=true,i=0;function loop(){i++;if(run)setTimeout(loop,0);};setTimeout(function(){run=false},1);loop();
    正如@Sirko所暗示的那样,为了达到您想要的效果,将当前时间戳保存在一个变量中,
    var start=(new Date())。getTime();
    然后在
    while
    语句中,从当前时间中减去该时间,并检查结果数字是否小于预期延迟。
    while((新日期()).getTime()-start
    。如果您只想查看Chrome的运行速度,请将while循环设置为以10000的增量运行。设置一个变量,如循环前的开始时间,循环后的当前时间,然后比较两者。“有时”正是堆栈为空时。这并不是因为javascript的单线程特性。即使这非常愚蠢,实现也可能是“检查每条指令之间的消息”毕竟,因为JS是一种解释性语言。这是因为事件循环实现,它在堆栈为空时被调用。@Guillo至于“有时”——这个概念被称为反讽,我想我用突出显示的“从不”来澄清。至于“消息之间”——我知道的每个JS引擎基本上都是单线程的(工人除外)。请参阅以获得更深入的分析。顺便说一句,大多数现代引擎只有在其更高级的功能失败时才返回到直接解释JS。调用JavaScript单线程时要小心,因为它具有处理多线程的能力。但是,标准执行是单线程的。