HTML5 requestAnimationFrame原理

目前的Web页面中,实现动画的方式有很多,比如

  • CSS3中的animation
  • JS中的setTimeOut
  • HTML5中的canvas

除此之外,HTML5中还提供了一个requestAnimationFrame,直译过来就是请求动画帧,弄懂这个东西之前,我们先来了解一下其他两个概念。

  • 相关概念

  • 1)屏幕刷新频率

        现在的显示器主要有两种:LCD(Liquid Crystal Display )和CRT(Cathode Ray Tube),LCD是液晶显示屏,CRT传统显示器。

CRT显示器的原理是靠电子束激发屏幕内表面的荧光粉来显示图像的,由于荧光粉被点亮后很快会熄灭,所以电子枪必须循环地不断激发这些点。电子束每秒击打荧光粉的次数就是屏幕刷新频率。

LCD显示器的原理是液晶在不同电压的作用下会呈现不同的光特性,由许多个页面构成,一个液晶就是一个象素,而在彩色液晶显示屏中则每个象素由红绿蓝三个液晶共同构成,液晶是一直保持亮的,所以对于LCD来说不存在闪烁现象。

  • 2)跳频丢帧

    以上,对于CRT显示器来说,屏幕会以1000s/60Hz ≈ 16.7ms的频率不断刷新,当我们执行setTimeout(fn,10)时(10ms更新一次),就会出现跳频丢帧。举个例子,使用setTimeout每10ms向下移动1px:

  • 第0ms:屏幕未刷新,setTimeout未执行
  • 第10ms:屏幕未刷新,setTimeout开始执行并设置top=1px
  • 第16.7ms:屏幕开始刷新,屏幕上的图像向下移动了1px, setTimeout 未执行
  • 第20ms:屏幕未刷新,setTimeout开始执行并设置top=2px
  • 第30ms:屏幕未刷新,setTimeout开始执行并设置top=3px
  • 第33.4ms:屏幕开始刷新,屏幕上的图像向下移动了3px, setTimeout未执行

    可以看到bottom=2px的动画没有被屏幕刷新出来,就是就是丢帧

  • 刷新间隔

        requestAnimationFrame的执行时机是由系统决定的,比如之前文中提到的60Hz,那就是≈16.7ms执行一次,如果是75Hz,那么这个时间间隔就变成了1000/75≈13.3ms,这样就可以避免丢帧现象,使用起来也非常简单。

    var tops = 0;
    var element = document.getElementById('SomeElementYouWantToAnimate');
    element.style.position = 'absolute';
    //回调函数
    function render() {
        tops += 1;
        element.style.top = tops + 'px';
        if (tops < 100) {
            //递归渲染
            window.requestAnimationFrame(render);
        }
    }

    //第一帧渲染
    window.requestAnimationFrame(render);
  • 优点

  1. CPU节能:setTimeout无论再何时,只要开始了就会一直执行,除非手动终止,而requestAnimationFrame在最小化或者当前页面未激活的状态下是停止执行的,当激活时,会从上次执行停止的地方继续执行,节省了CPU的开销。
  2. 函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。一个刷新间隔内函数执行多次时没有意义的,因为显示器每16.7ms刷新一次,多次绘制并不会在屏幕上体现出来,当然也可以自定义throttle方法,比如lodash._throttle()
  • 兼容性

    requestAnimationFrame在不同浏览器的表现各不相同,主要体现在前缀不同,当然,有人做了polyfill,可以了解一下其实现方式:github代码

猜你喜欢

转载自my.oschina.net/pandon/blog/1820000