为什么jQuery不使用requestAnimationFrame?

76
一些浏览器支持requestAnimationFrame,那么为什么不使用它呢?毕竟,它自从Google Chrome 10就开始支持了。尽管如此,jQuery似乎没有使用它。我找到了一个错误报告,但没有真正的解释?不过我相信jQuery团队有他们的理由。
他们为什么不使用这个很棒的API呢?

1
尽管jQuery Core没有使用requestAnimationFrame,但我在1.8中添加了钩子,允许您覆盖setInterval循环,从而可以安装requestAnimationFrame插件 - gnarf
最新版本的jQuery确实使用了requestAnimationFrame。在2016年6月发布的jQuery 3.0重新启用了它,这是自2011年9月jQuery 1.6.3禁用它以来的更新。 - Rory O'Kane
3个回答

77
票号#9381中,您可以阅读为什么他们在一段时间后停止使用requestionAnimationFrame
总结一下,问题在于动画没有运行(浏览器试图减少CPU负载)当窗口没有焦点时,如果窗口被隐藏,则可以,但是如果窗口是可见的,但不在焦点中,则不行。此外,动画队列堆积,窗口重新获得焦点后,事情变得疯狂。这将需要对代码进行丑陋的更改和/或更改人们添加到动画队列中的方式。因此,决定在有更好的方法之前删除支持。

29
从jQuery 1.8版本开始,我确保我们可以支持覆盖定时器循环,并编写了一个非常简单的插件,该插件将使用requestAnimationFrame替换setInterval。插件链接:https://github.com/gnarf37/jquery-requestAnimationFrame - gnarf
47
这主要是由于有些人会做一些愚蠢的事,比如 setInterval(function{ $('.slideshow).animate(...); }, 3000);。相反,他们应该等待每个动画结束后才排队进行第二个动画。这是一个简单的解决方法,如果实施了,我们所有人都可以得到更流畅、节省电池的动画效果。 - Paul Irish

12

鉴于其他答案和反对意见,我想在一个简单的幻灯片动画上测试一下:

http://brass9.com/nature

截至2013年,这里其他答案中的反对意见似乎不再具有重要性。我已经添加了

https://github.com/gnarf/jquery-requestAnimationFrame/blob/master/src/jquery.requestAnimationFrame.js

到我的现有动画代码中,并验证它正在开启并影响使用的淡入淡出动画。它是可靠的,甚至在后台窗口中,在Chrome 30、IE 11和FF 24中都能正常工作。在测试Android 2.3时,它似乎使用了polyfill并按预期工作。

jQuery 3

jQuery 3.0整合了requestAnimationFrame。基本上,jQuery可以很好地处理它,但有些用户会调用.setInterval(function() { tag.animate(,从而搞砸它。因此,这个功能被列为主要版本发布。jQuery 3不支持IE8及以下版本,所以如果您有IE8用户,请使用jQuery 1.x。

CSS过渡

在我的测试中,requestAnimationFrame的CPU/电池节省效果是虚假的承诺。例如,在长时间淡出时,我看到它的CPU使用率很高。真正节省CPU/电池的是CSS过渡,可能是因为浏览器(特别是移动浏览器)能够对您的意图和其他被要求的内容进行更强的假设,本地代码仍然比Javascript+DOM更快速。

如果你真的想节省CPU/电池,那么CSS过渡就是为你准备的。IE9及以下版本无法处理它们,而且还有很多用户在使用,因此考虑使用jquery.transit,并在页面底部使用animate作为回退。


2
这是真的,我可以看到滑块在窗口失去焦点时淡出 - 至少在Chrome中。 - David Meister

6
在jQuery 1.6.2源代码中,如果requestAnimationFrame存在,则会使用它。我没有详细研究代码以确定它是否被用于所有可以使用的内容,但它在动画部分的代码中被使用,而不是调用setInterval()。以下是1.6.2版本的代码:
// Start an animation from one number to another
custom: function( from, to, unit ) {
    var self = this,
        fx = jQuery.fx,
        raf;

    this.startTime = fxNow || createFxNow();
    this.start = from;
    this.end = to;
    this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
    this.now = this.start;
    this.pos = this.state = 0;

    function t( gotoEnd ) {
        return self.step(gotoEnd);
    }

    t.elem = this.elem;

    if ( t() && jQuery.timers.push(t) && !timerId ) {
        // Use requestAnimationFrame instead of setInterval if available
        if ( requestAnimationFrame ) {
            timerId = true;
            raf = function() {
                // When timerId gets set to null at any point, this stops
                if ( timerId ) {
                    requestAnimationFrame( raf );
                    fx.tick();
                }
            };
            requestAnimationFrame( raf );
        } else {
            timerId = setInterval( fx.tick, fx.interval );
        }
    }
},

我还没有使用1.6.4,所以不清楚那个版本的情况。如果在那个版本中不存在,那么肯定存在一些问题,因此被移除了。
编辑:
如果你阅读这篇博客文章,听起来它已经从1.6.3中移除,也许会重新出现在1.7中,主要原因是它破坏了一些人“错误”使用动画队列的东西(尽管这可能是一个观点问题)。

请查看http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js。我已经搜索了`requestionAnimationFrame`,但没有找到匹配项。 - Randomblue
在1.8版本之后添加回来的正确方法是使用类似于我的插件:https://github.com/gnarf/jquery-requestAnimationFrame - gnarf

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