5

在使用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));
}

但是当我阅读并尝试自己时,时间不是 1ms ,它至少是 10ms 之类的。事实上,在 10 秒后,我的值 i 约为 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 带来了很大压力,但至少它出人意料地加快了速度。

我阅读了您在论坛中的所有回复和其他任务,他们证实了我的想法。但真正的问题是为什么!为什么他们将限制设置为 15 毫秒,而我可以进行多次连续调用以获得更低的时间?我确信这个多重回调系统不是好的做法,但我可以做到,而且我可能会使 CPU 负载饱和。

4

5 回答 5

8

不,Javascript 是单线程的。当您运行setIntervalorsetTimeout时,会生成一个事件,然后将其添加到浏览器的执行队列中。因此,虽然您不能保证代码本身会在您希望它运行时准确地运行,但您可以确定每次应该生成事件时都会生成事件。因此,在这种情况下,您有 12 个正在生成的事件彼此非常接近。我注意到您已用作1间隔值。但是,大多数浏览器中的最小值在附近15(有关更多信息,请参见此处。)浏览器将按照事件在执行队列中的顺序运行事件(在 中setInterval,事件试图赶上。看看答案Marcel 链接到,以获取更多详细信息)。

这意味着在第一种情况下,您每 15 毫秒左右生成一个事件。所以计数器增加得更慢。但是在第二种情况下,您有12 个事件,它们每 15 毫秒左右就会彼此非常接近地触发,因此计数器的增量要快得多。

于 2010-10-27T21:20:23.390 回答
2

在大多数浏览器中,JavaScript 计时器值至少设置为 15 毫秒,即使给出了较小的值。AFAIK 只有 Google Chrome 使用 4ms。另请参阅如何确定在 JavaScript 动画循环中使用的最佳“帧速率”(setInterval 延迟)的公认答案?.

于 2010-10-27T21:15:01.750 回答
1

不,JavaScript 没有多线程,至少目前没有。

请阅读此答案以了解其setInterval工作原理。

于 2010-10-27T21:17:59.373 回答
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 性能,您会发现它几乎没有工作,这意味着较低的速率不是由于代码繁忙。它根本不会像您要求的那样频繁地触发间隔。

(如果你开始 12 个间隔,负载仍然几乎不明显。我开始了 200 个间隔,然后在其中一个核心上获得接近 100% 的负载。)

浏览器使用某种时钟来确定应该触发哪些间隔,并且该时钟的分辨率通常低于毫秒。因此,在下一个时钟滴答之前,间隔不会再次触发,在您的情况下,这似乎相隔大约 15 毫秒。

于 2010-10-27T21:33:45.043 回答
0

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

即便如此,作为最小值的第二项充分解释了第一个样本。

此行为也解释了第二个示例。您调用的每个setInterval方法都会注册一个完全独立的回调。它们每个都至少有 1,但彼此不依赖。因此,它们在相同的 1 毫秒间隔内触发是完全有效的(只要每个本身在重新触发之前等待 1 毫秒)。

于 2010-10-27T21:17:05.043 回答