setInterval 的时间似乎不准确

Timing on setInterval doesn't seem accurate

我正在写一些 javascript 来更改当前显示的图像的不透明度,使其看起来像是褪色,然后将图像更改为不同的图像。我将 setInterval 的图像更改设置为等待 5000 毫秒。淡入淡出的 setInterval 设置为从 4000 毫秒开始。 setTimeout 被调用 10 次,全部等待 100 毫秒,弥补了 fading setInterval 预先等待的时间与 ChangeImage setInverval 预先等待的时间之间的差异。

var num, lastNum = 0, count = 10, tcount = 0.0;
var file = "images/image-", ext = ".jpg", image, temp;
var f1 = "alpha(opacity=", f2 = ")";

window.onload = setTimeout(Initialize, 0);
window.onload = setInterval(ImageFader, 4000);
window.onload = setInterval(ChangeImage, 5000);

function Initialize()
{
    image = document.getElementById('title-image');
    image.src = "images/image-1.jpg";
}

function ChangeImage()
{
    image = document.getElementById('title-image');
    do
    {
        num = Math.floor((Math.random() * 10) + 1);
    } while (num == lastNum);
    lastNum = num;
    temp = file.concat(num.toString());
    image.src = temp.concat(ext);
}

function ImageFader()
{
    setTimeout(Fade, 100);
}

function Fade()
{
    tcount = count / 10;
    image.style.opacity = tcount;
    f1 = f1.concat((tcount * 100).toString());
    image.style.filter = f1.concat(f2);

    if (count > 1)
    {
        count--;
        setTimeout(Fade, 100);
    }
    else
    {
        count = 10;
        image.style.opacity = 1;
        image.style.filter = "alpha(opacity=100)";
    }
}

我真的很困惑为什么时代不合时宜。第一张图像的褪色时间恰到好处。它消失的地方,然后在正确的时间移动到下一个图像。但从那时起,时间就变得不同步了。褪色发生但图像没有在正确的时间改变。

Fade() 方法的执行时间肯定是问题的一部分。

还有你所处的环境。 Real-time operating systems 承诺一定时间完成的事情,每次都按时执行。 (除了一些例外。我正在简化。)

类似地,没有任何 OS 的嵌入式系统可以非常可预测 - 因为代码行之间没有任何事情发生。如果你能准确地判断出A点和B点之间发生了多少CPU个循环,你就可以保证一切都会按时发生。

您正在做的是尝试在尽可能远离嵌入式系统的环境中使用非实时操作系统实现如此精确的计时!

即使我们忽略了这样一个现实,即您的操作系统(托管浏览器)永远不会保证事情会在您希望的时候发生(您无法在其中解决) JS 在这样的浏览器中)你仍然有问题 - setTimeout(Fade, 100) 行实际上给你更多的延迟 100.5ms,因为所有这些代码都必须首先执行:

tcount = count / 10;
image.style.opacity = tcount;
f1 = f1.concat((tcount * 100).toString());
image.style.filter = f1.concat(f2);

if (count > 1)
{ ...

(我希望这是有道理的。该函数中导致 setTimeout(...) 的每一行代码都需要时间来执行,这就是我的观点。)

如果您的问题只是两个函数的 相对计时 超出(而不是 5000 毫秒永远不会精确到 5000 毫秒),那么有一个非常简单的解决方案。

从一个计时器开始做所有事情。 :-)

创建一个"clock",其间隔是所有其他时钟间隔的公共分度。 100ms 在你的情况下就足够了,因为它可以乘以整数为 5000ms、4000ms 和 100ms。

废弃所有这些其他代码行:

window.onload = setTimeout(Initialize, 0);
window.onload = setInterval(ImageFader, 4000);
window.onload = setInterval(ChangeImage, 5000);

改为计算一个 100 毫秒时钟的执行次数。该时钟的 50 次执行应触发 ChangeImage,40 次执行应触发 ImageFader,等等

这会给你精确的相对时间。


更新以包含示例伪代码:

var clockCount = 0;
var fading = false;

setTimeout(globalClock, 100);
function globalClock(
   clockCount++;

   if (clockCount == 40) {
      ImageFader();
   } elseif (clockCount == 50) {
      ChangeImage();
   }

   if (fading) {
      Fade();
   }

   // At end of function so we don't ever trigger multiple executions at the same time
   setTimeout(globalClock, 100);
);

删除 setInterval() 调用,仅使用 setTimeout(),将所有计时器组织到链中:

  1. Initialize()的末尾调用setTimeout(Fade, 4000)

  2. 多次从 Fade() 本身调用 setTimeout(Fade, 100),但 setTimeout(ChangeImage, 100) 在最后一步。

  3. ChangeImage()的末尾调用setTimeout(Fade, 4000)

以下是我使用单独的 setInverval() 方法进行淡入淡出和图像更改的方法:

window.onload = setTimeout(Initialize, 0);
window.onload = setInterval(ImageFader, 8000);

function Initialize()
{
    image = document.getElementById('title-image');
    image.src = "images/image-1.jpg";
}

function ChangeImage()
{
    image = document.getElementById('title-image');
    do
    {
        num = Math.floor((Math.random() * 10) + 1);
    } while (num == lastNum);
    lastNum = num;
    temp = file.concat(num.toString());
    image.src = temp.concat(ext);
}

function ImageFader()
{
    setTimeout(Fade, 100);
}

function Fade()
{
    tcount = count / 10;
    image.style.opacity = tcount;
    f1 = f1.concat((tcount * 100).toString());
    image.style.filter = f1.concat(f2);

    if (count > 1)
    {
        count--;
        setTimeout(Fade, 100);
    }
    else
    {
        count = 10;
        ChangeImage();
        image.style.opacity = 1;
        image.style.filter = "alpha(opacity=100)";
    }
}