如何使用requestAnimationFrame实现相对稳定的帧率?

9

我正在尝试使用requestAnimationFrame,但在除了Chrome以外的任何其他浏览器中都得到了非常卡顿的动画。

我创建了一个像这样的对象:

var object = function() {

    var lastrender = (new Date()).getTime();
    var delta = 0;

    return {

        update: function() {
             //do updates using delta value in calculations.
        },

        loop: function() {
            var looptimestamp = (new Date()).getTime();
            delta = looptimestamp - lastrender;
            lastrender = looptimestamp;

            this.update();

            window.requestAnimationFrame(this.loop.bind(this));
        }
    };
}

现在我只是在画布元素上绘制一个矩形,并将其移动。这是处理器上非常轻量级的操作。在Chrome中,它运行得非常流畅,当我在控制台记录delta值时,它几乎始终保持在约17左右。然而,如果我在Firefox或Safari中执行相同的操作,则会得到以下delta值:

17-3-17-2-32-34-32-31-19-31-17-3-0-14-3-14-35-31-16-3-17-2 ... and so on

看起来浏览器与显示屏之间的同步不太好,除了Chrome之外,在所有其他情况下,使用旧的setTimeout方法并将目标超时设置为16ms可以获得更平滑的动画。

有人知道是否可能在除Chrome之外的浏览器中使用requestAnimationFrame获得更平滑的动画吗?有人在Firefox中成功获得比上面发布的更稳定的delta值吗?


2
你在做什么类型的动画?建议使用jsfiddle来实现。 - Raptor
你研究过 CSS 过渡效果吗?它们使用 GPU 进行渲染,产生的浏览器特效非常流畅。你可以在这里试用一下:http://www.css3maker.com/css3-transition.html - Teodor Sandu
你应该提供你实际正在进行的动画。这可能与循环本身无关,而是与你如何绘制和平移对象有关... - Dnaso
其他浏览器非常慢,而Chrome非常快。如果您的代码有任何可以改进的地方,除了Chrome之外的浏览器都无法优化该代码,您将会看到这一点。*注意:这是一个通用语句,不总是正确的,但通常是正确的。 - SgtPooki
我认为您省略了问题代码。您能展示一下 object.update() 中的代码吗?您可能会导致大量重排,这会影响性能。通常您可以使用Chrome开发者工具中的时间轴来查找是什么导致了拖慢效果。 - doug65536
显示剩余3条评论
2个回答

4
您的动画流畅帧率降低的原因是由于浏览器对canvas的内存控制。我不知道浏览器性能的真实细节,但火狐浏览器几乎立即出现帧率下降,而在谷歌浏览器中,下降发生在一段时间之后。
帧率下降的真正问题是由于canvas元素占用的内存。每次您向canvas绘制内容时,该操作都会保存到canvas的路径中。每次在canvas上绘制内容时,路径就会占用更多的内存。如果您不清空canvas的路径,就会导致帧率下降。使用context.clearRect(x, y, w, h);无法清除canvas路径,您需要使用context.beginPath();开始一个新的路径来重置canvas路径。例如:
// function that draws you content or animation
function draw(){
    // start a new path/empty canvas path
    canvas.beginPath(); 

    // actual drawing of content or animation here 
}

0

如果 delta < 阈值,你可以跳过更新以获得更流畅的动画,例如:

if (delta > 5) this.update();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接