如何让setTimout函数以相同的速度运行?

时间:2012-01-27 14:58:59

标签: javascript optimization time

前言:我的个人网站上有demo of the problem(我希望这没关系。如果没有,我可以尝试在jsfiddle上设置它)。我打算让这个问题变得有趣,同时也试图理解javascript中函数的时间。

我在超时时递增进度条的值。理想情况下(如果函数瞬间运行)它们应该以相同的速度填充,但在现实世界中,它们不会。代码是这样的:

function setProgress(bar, myPer) {
bar.progressbar({ value: myPer })
    .children('.ui-progressbar-value')
        .html(myPer.toPrecision(3) + '%')
            .attr('align', 'center');
    myPer++;
    if(myPer == 100) { myPer = 0; }
 }

 function moveProgress(bar, myPer, inc, delay){
    setProgress(bar, myPer);
    if(myPer >= 100) { myPer = 0; }
    setTimeout(function() { moveProgress(bar, myPer+inc, inc, delay); }, delay);
 }

 $(function() { 
   moveProgress($(".progressBar#bar1"), 0, 1, 500);
   moveProgress($(".progressBar#bar2"), 0, 1, 500);
   moveProgress($(".progressBar#bar3"), 0, .1, 50);
   moveProgress($(".progressBar#bar4"), 0, .01, 5);             
 });

天真地,人们会认为应该以相同的速度运行(填充进度条)。

然而,在前两个栏中,(如果我们将“设置进度条”称为单个操作)我每500毫秒执行一次操作,总共500次操作以填充栏;第三,我每50毫秒进行一次操作,总共进行5,000次操作以填补空白;在第四场比赛中,我每5分钟执行一次操作,总计50,000次操作,以填补空缺。

我的代码的哪一部分耗时最长,导致这些速度差异,并且可以更改以使它们看起来以它们的方式运行(第四个条形图获得较小的增量),但也可以在同样的速度?

3 个答案:

答案 0 :(得分:3)

使用setTimeout这样的事情的最大问题是您的代码执行发生在超时之间,并且不会在发送给setTimeout的值中考虑到。如果你的延迟是5毫秒而你的代码需要5毫秒才能执行,那么你的时间基本上就会翻倍。

另一个因素是,一旦你的超时触发,如果另一段代码已经在执行,它将不得不等待它完成,延迟执行。

这与人们在尝试将setTimeout用于时钟或秒表时遇到的问题非常相似。解决方案是将当前时间与程序开始的时间进行比较,并根据该时间计算时间。你可以做类似的事情。检查自启动以来的时间长度,并根据该值设置%。

答案 1 :(得分:0)

导致速度差异的原因有两点:首先是你执行更多代码来填充底栏(正如你在第2段到最后一段中提到的那样)。此外,每次设置超时时,浏览器都会将其排队...实际延迟可能比您指定的时间长,具体取决于队列中的数量(请参阅MDN on window.setTimeout)。

答案 2 :(得分:0)

喜欢这个问题,我没有一个非常准确的答案,但这是我的2美分:

Javascript是一种非常快速的语言,可以很好地处理它的事件循环,因此在早餐时吃setTimeouts和setIntervals。
但是有一些限制,它们取决于很多因素,例如浏览器和计算机速度,事件循环中的函数数量,执行代码的复杂性和超时值......

在这种情况下,我认为很明显,如果你尝试每500毫秒执行一个函数,它的表现要好于每50毫秒执行一次,因此比每5毫秒好很多。如果考虑到您将它们全部运行在一起,您可以预测性能将不是最佳的。

你可以尝试这个练习:
拿500ms一个,然后单独运行。标记填充栏所需的总时间(在此处您将看到它将比预期花费更长的时间)。
尝试同时执行两个500毫秒的超时,并看到总时间变得更长一点 如果你加50ms,然后加5ms,你就会发现每次都会失去性能......