JavaScript setTimeout()在负载很重的情况下变慢

时间:2009-07-30 20:33:05

标签: javascript settimeout

我创建了一个淡化元素背景颜色的脚本。我使用setTimeout()每5毫秒对颜色进行一次增量更改。如果我只是一次淡化一件事的背景颜色,那么脚本效果很好,但是如果我有50个元素,我一下子都褪色,速度比5毫秒慢得多,因为所有并发setTimeout()一次运行。例如,如果我一次淡化50个元素,通常应该在1秒内执行的淡入淡出可能需要30秒。

我有什么想法可以解决这个问题?

如果有人有想法,这是脚本:

function fadeBackground(elementId, start, end, time) {
    var iterations = Math.round(time / 5);

    var step = new Array(3);

    step[0] = (end[0] - start[0]) / iterations;
    step[1] = (end[1] - start[1]) / iterations;
    step[2] = (end[2] - start[2]) / iterations;

    stepFade(elementId, start, step, end, iterations);
}

function stepFade(elementId, cur, step, end, iterationsLeft) {
    iterationsLeft--;

    document.getElementById(elementId).style.backgroundColor
        = "rgb(" + cur[0] + "," + cur[1] + "," + cur[2] + ")";

    cur[0] = Math.round(end[0] - step[0] * iterationsLeft);
    cur[1] = Math.round(end[1] - step[1] * iterationsLeft);
    cur[2] = Math.round(end[2] - step[2] * iterationsLeft);

    if (iterationsLeft > 1) {
        setTimeout(function() {
            stepFade(elementId, cur, step, end, iterationsLeft);
        }, 5);
    }
    else {
        document.getElementById(elementId).style.backgroundColor 
            = "rgb(" + end[0] + "," + end[1] + "," + end[2] + ")";
    }
}

它的使用方式如下:

fadeBackground("myList", [98,180,232], [255,255,255], 1000);

3 个答案:

答案 0 :(得分:11)

以下是来自Google的article,其中作者讨论了他们针对Gmail定时器的工作。他们发现,使用单个高频定时器比使用多个定时器更快,如果它们使用了大量且快速的定时器。

你可以有一个每5ms触发一次的计时器,并将需要淡化的所有元素添加到一个数据结构中,该数据结构跟踪它们在淡入淡出过程中的位置。然后,您的一个计时器可以查看该列表,并在每次触发时为每个元素执行下一个淡入淡出。

另一方面,您是否尝试过使用像MootoolsJQuery这样的库而不是滚动自己的动画框架?他们的开发人员在优化这些操作方面付出了很多努力。

答案 1 :(得分:4)

首先,您的脚本没有考虑到最小超时通常为10-15ms,具体取决于浏览器。你可以看到my post on this topic。在里面你会找到一个流行浏览器的表格和一个测量它的程序的链接,所以你可以自己验证声明。我很遗憾地说,但每5ms迭代一次是一厢情愿的想法。

其次,计时器不是中断。它们没有神奇之处 - 它们无法中断浏览器中正在运行的任何内容并执行其有效负载。相反,它们将被推迟到运行代码完成并且浏览器恢复控制并运行计时器的能力。淡化50个元素需要时间,我敢打赌它超过5毫秒,特别是如果你考虑浏览器的整个延迟模型:你更新DOM,浏览器将在某个时间点更新其可视化表示。

我想以积极的方式结束:

  • 不要淡出50个单独的元素,尝试将它们分组并淡化其父级 - 它可以更快。
  • 在UI上更具创意。尝试提出一个解决方案,它不需要一次淡出很多独立元素。
  • 在围绕它们进行设计之前,请务必确认您的背景假设是否正确。
  • 如果可以,请尝试定位现代浏览器。根据我的个人经验,谷歌浏览器非常适合定时器,其JavaScript引擎(V8)非常快。

答案 2 :(得分:0)

除了其他答案之外,这里还有John Resig关于计时器的优秀文章:http://ejohn.org/blog/how-javascript-timers-work/