setInterval的这种行为是否意味着Javascript中的多线程行为?

时间:2010-10-27 21:05:44

标签: javascript multithreading setinterval

在使用javascript时我注意到了这件事。你可以使用

var i=0; 
var startingTime=new Date().getTime();
setInterval("foo()",1);
function foo() {
    i+=1;
    if ($("#foodiv").text()==i) {
        //we detected a doubled value (parallel execution)
        $("#repdiv").append("[repetition on "+i+"]");
    }
    $("#foodiv").html(i);
    $("#timediv").html(Math.floor((new Date().getTime()-startingTime)/1000));
}

但是当我阅读并尝试自己时,时间不是1毫秒,它至少是10毫秒或者其他东西。事实上,在10秒后,我的值大约为2300/2400,而不是预期的10000.

这是程序的最小可能时间因素???肯定没有。如果我试试这个:

<html><head>
<script language="javascript" type="text/javascript" src="jquery-1.4.min.js"></script>
<script type="text/javascript">

var i=0;
var startingTime=new Date().getTime();

setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);
setInterval("foo()",1);setInterval("foo()",1);setInterval("foo()",1);

function foo() {
    i+=1;
    if ($("#foodiv").text()==i) {
        //we detected a doubled value (parallel execution)
        $("#repdiv").append("[repetition on "+i+"]");
    }
    $("#foodiv").html(i);
    $("#timediv").html(Math.floor((new Date().getTime()-startingTime)/1000));

}
</script>
</head>
<body>
<div id="foodiv"></div>  (counter)
<br/>
<div id="timediv"></div> (seconds passed)
<br/>
<div id="repdiv"></div>
<br/>
</body>
</html>

计数器将非常快,10秒后,我的值为12000 !!!!这对我来说是无法解释的,因为调用不是并行执行的(或者至少我们可以为不同的调用设置一些加倍的i值,在repdiv div中计算)。

有人可以解释一下吗?我知道cpu在所有这些调用中都非常紧张,但至少它会令人惊讶地加快速度。

我在论坛中阅读了你的所有回复和其他任务,他们证实了我的想法。但真正的问题是为什么!当我可以进行多次顺序调用以获得更低的时间时,为什么他们将限制设置为15ms?我敢肯定这个多回调系统并不是一个好习惯,但我可以做到,而且我可能会使cpu负载饱和。

5 个答案:

答案 0 :(得分:8)

不,Javascript是单线程的。运行setIntervalsetTimeout时,会生成一个事件,然后将其添加到浏览器的执行队列中。因此,虽然您无法保证代码本身在您希望它运行时完全运行,但您可以确保每次生成事件时都会生成该事件。因此,在这种情况下,您生成的12个事件彼此非常接近。我注意到您已使用1作为间隔值。但是,大多数浏览器中的最小值大约为15(有关详细信息,请参阅here。)浏览器将按照它们在执行队列中的顺序运行事件(在setInterval中,事件试图追赶。看看Marcel链接的答案,更多细节)。

这意味着在第一个场景中,您每隔15毫秒就会生成一个事件。因此计数器增加得更慢。但在第二种情况下,你有十二个事件,这些事件每隔15毫秒就会相互接近,因此计数器的增量会快得多。

答案 1 :(得分:2)

在大多数浏览器中,JavaScript计时器值设置为至少15毫秒,即使给出的值较小。 AFAIK只有谷歌Chrome使用4毫秒。另请参阅How to determine the best "framerate" (setInterval delay) to use in a JavaScript animation loop?的接受答案。

答案 2 :(得分:1)

不,JavaScript没有多线程,至少现在没有。

请阅读this answer,了解setInterval的工作原理。

答案 3 :(得分:1)

您发布的代码未运行,此处是更正后的代码:

var i=0; 
setInterval(foo,1);

function foo() {
  i+=1;
  if ($("#foodiv").text()==i) {
    //we detected a doubled value (parallel execution)
    $("#repdiv").append("[repetition on "+i+"]");
  }
  $("#foodiv").html(i);
}

如果在代码运行时查看CPU性能,您会发现它几乎没有工作,这意味着较低的速率不是由于代码繁忙。它根本不会按照你的要求频繁发射间隔。

(如果你开始十二个时间间隔,负载仍然很难显示。我开始了200个间隔,然后在其中一个核心上接近100%的负载。)

浏览器使用某种时钟来确定应该触发的时间间隔,并且该时钟通常具有比毫秒更低的分辨率。因此,间隔将不会再次触发,直到下一个时钟滴答,在您的情况下似乎相隔约15毫秒。

答案 4 :(得分:0)

传递给setInterval方法的第二个值确实是最小值。虽然1代表1毫秒,但大多数浏览器不太可能给你这个超时。另一个答案是它更可能在15毫秒左右。

即使如此,第二项是最小值,也可以解释第一个样本。

此行为也解释了第二个样本。您调用的每个setInterval方法都会注册一个完全独立的回调。它们各自至少有1但彼此没有依赖关系。所以它们在相同的1毫秒间隔内发射是完全有效的(只要每个间隔在重新发射之前等待1毫秒)。