zoukankan      html  css  js  c++  java
  • 更好的逐帧动画函数 — requestAnimationFrame 简介

    本文将会简单讲讲 requestAnimationFrame 函数的用法,与 setTimeout/setInterval 的区别和联系,以及当标签页隐藏时 requestAnimationFrame、setTimeout 各自的后续渲染。

    requestAnimationFrame

    说到 requestAnimationFrame,不得不提到 canvas 动画,而说到 canvas 动画,又不得不说到 setTimeout/setInterval。

    canvas 动画是基于逐帧重绘的,我们可以用 setTimeout 或者 setInterval 函数,设置定时器,每过一定时间,完成数据更新,继而重绘到画布上。但是这样做有个缺点,可能会有卡顿。举个简单的例子,假设浏览器一秒刷新 10 次(正常的浏览器都在 60 fps 左右),重绘的时间点为 0ms,100ms,200ms,300ms .. 1000ms,用 setInterval 来做动画,间隔设置为 60ms,也就是每 60ms 更新数据,那么数据更新点为 60ms,120ms,180ms,240ms ... ,100ms 的时候实际更新了一次数据,200ms的时候实际已经更新了三次数据,恩,理论上会出现不流畅的情况(如果没有听懂,可以参考下张鑫旭大神的文章 CSS3动画那么强,requestAnimationFrame还有毛线用?有个很好的比喻)。what'more,setTimeout/setInterval 的时间间隔并不是像传的参数那般准确,事实上,setTimeout 间隔通常会大于所传的数,而 setInterval 可能会因为丢失回调而小于所定数字,具体可以看下 从setTimeout谈JavaScript运行机制

    这时候,我们设想,如果浏览器在重绘前,通知客户端数据更新,那就太棒了!requestAnimationFrame 函数闪亮登场!requestAnimationFrame 是浏览器用于定时循环操作的一个接口,类似于 setTimeout,主要用途是按帧对网页进行重绘。设置这个 API 的目的是为了让各种网页动画效果(DOM 动画、Canvas 动画、SVG 动画、WebGL 动画)能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。代码中使用这个 API,就是告诉浏览器希望执行一个动画,让浏览器在下一个动画帧安排一次网页重绘。

    使用方式非常简单,现代浏览器已经支持无前缀的 API,低版本的现代浏览器可以用带前缀的 API 回退,低版本 ie 可以用 setTimeout 回退(具体兼容性可以参考 http://caniuse.com/#search=requestAnimationFrame):

    window.requestAnimFrame = (function() {  
      return  window.requestAnimationFrame ||   
        window.webkitRequestAnimationFrame ||   
        window.mozRequestAnimationFrame    ||   
        window.oRequestAnimationFrame      ||   
        window.msRequestAnimationFrame     ||   
        function(callback){  
          window.setTimeout(callback, 1000 / 60);  
        }; 
    })();  
    

    一个简单的使用:

    // 调用 相当于setTimeout里的callback
    function animationLoop(){   
      // logic  
      document.body.innerHTML = currentnumber++; 
      // 循环
      requestID = requestAnimFrame(animationLoop);
    }  
    
    // start
    requestID = requestAnimFrame(animationLoop);
    

    跟 setTimeout 一样,RAF 也可以取消掉。非常简单,以上面代码为例,将 requestID 传入 cancelAnimationFrame 函数即可:

    window.cancelAnimationFrame(requestID);
    

    事实上,我还是比较习惯用一个变量来表示是否继续重绘:

    // 调用 相当于setTimeout里的callback
    function animationLoop(){   
      // logic  
      document.body.innerHTML = currentnumber++; 
      // 循环
      if (flag) // 继续重绘直到 flag === false
        requestID = requestAnimFrame(animationLoop);
    } 
    

    有一个完整的 polyfill,可以参考下谷歌大神的这篇文章 requestAnimationFrame for Smart Animating

    标签页隐藏时

    RAF 宣称,使用这个 API,一旦页面不处于浏览器的当前标签,重绘频率则会大大降低。大大降低到底是降低到什么程度?出于好奇,我决定进一步探索下。

    做法非常简单,将标签页隐藏,然后看看刷新频率,输出前后两个刷新的间隔时间。

    chrome,当标签页隐藏时,不再继续刷新。firefox 中,间隔时间如下:

    1017
    1997
    3998
    7999
    15993
    32000
    63994
    127999
    

    很明显的指数型增长趋势。

    setTimeout/setInterval 呢?当标签页被隐藏时还是一样工作吗?经测试(仅在 firefox & chrome 下测试),当时间间隔大于 1000ms 时,如果标签页被隐藏,还是按照设定的时间执行回调;如果时间间隔小于 1000ms,当标签页被隐藏时,时间间隔会被延迟到 1000ms 执行回调。

    Read More:

  • 相关阅读:
    Spring Cloud Hystrix Dashboard的使用 5.1.3
    Spring Cloud Hystrix 服务容错保护 5.1
    Spring Cloud Ribbon 客户端负载均衡 4.3
    Spring Cloud 如何实现服务间的调用 4.2.3
    hadoop3.1集成yarn ha
    hadoop3.1 hdfs的api使用
    hadoop3.1 ha高可用部署
    hadoop3.1 分布式集群部署
    hadoop3.1伪分布式部署
    KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机
  • 原文地址:https://www.cnblogs.com/lessfish/p/5208171.html
Copyright © 2011-2022 走看看