前言

在研究canvas的2D pixi.js库的时候,其动画的刷新都用requestAnimationFrame替代了setTimeout 或 setInterval

但是jQuery中还是采用了setInterval,我这章就研究下顺便改造下jQuery的动画

定时器

jQuery动画的实现考虑到兼容与易用性采用了setInterval来不断绘制新的属性值,从而达到动画的效果。

大部分浏览器的显示频率是16.7ms,由于浏览器的特性,setInterval会有一个丢帧的问题

即使向其传递毫秒为单位的参数,它们也不能达到ms的准确性。这是因为javascript是单线程的,可能会发生阻塞

jQuery会有一个全局设置jQuery.fx.interval = 13 设置动画每秒运行帧数。

默认是13毫秒。该属性值越小,在速度较快的浏览器中(例如,Chrome),动画执行的越流畅,但是会影响程序的性能并且占用更多的 CPU 资源

那么归纳一点最关键的问题:

  1. 开发着并不知道下一刻绘制动画的最佳时机是什么时候

requestAnimationFrame

requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API

说简单点

  • setInterval、setTimeout是开发者主动要求浏览器去绘制,但是由于种种问题,浏览器可能会漏掉部分命令
  • requestAnimationFrame 就是浏览器什么要开始绘制了浏览器自己知道,通过requestAnimationFrame 告诉开发者,这样就不会出现重复绘制丢失的问题了

目前已在多个浏览器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,

唯一比较遗憾的是目前安卓上的原生浏览器并不支持requestAnimationFrame,不过对requestAnimationFrame的支持应该是大势所趋了,安卓版本的chrome 16+也是支持requestAnimationFrame的。

比较

区别:

  1. requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧
  2. 隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
  3. requestAnimationFrame也会像setTimeout一样有一个返回值ID用于取消,可以把它作为参数传入cancelAnimationFrame函数来取消requestAnimationFrame的回调

兼容处理

摘自HTML5 Canvas 核心技术

  1. window.requestNextAnimationFrame = (function () {
  2. var originalWebkitRequestAnimationFrame = undefined,
  3. wrapper = undefined,
  4. callback = undefined,
  5. geckoVersion = ,
  6. userAgent = navigator.userAgent,
  7. index = ,
  8. self = this;
  9.  
  10. // Workaround for Chrome 10 bug where Chrome
  11. // does not pass the time to the animation function
  12.  
  13. if (window.webkitRequestAnimationFrame) {
  14. // Define the wrapper
  15.  
  16. wrapper = function (time) {
  17. if (time === undefined) {
  18. time = +new Date();
  19. }
  20. self.callback(time);
  21. };
  22.  
  23. // Make the switch
  24.  
  25. originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame;
  26.  
  27. window.webkitRequestAnimationFrame = function (callback, element) {
  28. self.callback = callback;
  29.  
  30. // Browser calls the wrapper and wrapper calls the callback
  31.  
  32. originalWebkitRequestAnimationFrame(wrapper, element);
  33. }
  34. }
  35.  
  36. // Workaround for Gecko 2.0, which has a bug in
  37. // mozRequestAnimationFrame() that restricts animations
  38. // to 30-40 fps.
  39.  
  40. if (window.mozRequestAnimationFrame) {
  41. // Check the Gecko version. Gecko is used by browsers
  42. // other than Firefox. Gecko 2.0 corresponds to
  43. // Firefox 4.0.
  44.  
  45. index = userAgent.indexOf('rv:');
  46.  
  47. if (userAgent.indexOf('Gecko') != -) {
  48. geckoVersion = userAgent.substr(index + , );
  49.  
  50. if (geckoVersion === '2.0') {
  51. // Forces the return statement to fall through
  52. // to the setTimeout() function.
  53.  
  54. window.mozRequestAnimationFrame = undefined;
  55. }
  56. }
  57. }
  58.  
  59. return window.requestAnimationFrame ||
  60. window.webkitRequestAnimationFrame ||
  61. window.mozRequestAnimationFrame ||
  62. window.oRequestAnimationFrame ||
  63. window.msRequestAnimationFrame ||
  64.  
  65. function (callback, element) {
  66. var start,
  67. finish;
  68.  
  69. window.setTimeout(function () {
  70. start = +new Date();
  71. callback(start);
  72. finish = +new Date();
  73.  
  74. self.timeout = / - (finish - start);
  75.  
  76. }, self.timeout);
  77. };
  78. }());
  79.  
  80. window.cancelNextRequestAnimationFrame = window.cancelRequestAnimationFrame
  81. || window.webkitCancelAnimationFrame
  82. || window.webkitCancelRequestAnimationFrame
  83. || window.mozCancelRequestAnimationFrame
  84. || window.oCancelRequestAnimationFrame
  85. || window.msCancelRequestAnimationFrame
  86. || clearTimeout;

对比

通过requestAnimationFrame与setInterval同样的效果对比

一段动画采用setInterval与requestAnimationFrame,分别给出了webKit下调用刷新的次数

setInterval实现,调用了144次左右



<!doctype html><img id="book" style="background:red;opacity:1;position: relative; left: 500px;" alt="" width="100" height="123" data-mce-style="background: red; opacity: 1; position: relative; left: 500px;" /><div id="several"><br /></div><script type="text/javascript">

var book = document.getElementById('book')
var several = document.getElementById('several');

animate(book, {
left: 50,
duration: 2000
})

function animate(elem, options){
//动画初始值
var start = 500
//动画结束值
var end = options.left
//动画id
var timerId;
var createTime = function(){
return (+new Date)
}
//动画开始时间
var startTime = createTime();

var i = 0;

function tick(){
i++;
several.innerHTML = 'setInterval调用次数:' + i;
//每次变化的时间
var remaining = Math.max(0, startTime + options.duration - createTime())
var temp = remaining / options.duration || 0;
var percent = 1 - temp;
var stop = function(){
//停止动画
clearInterval(timerId);
timerId = null;
}
var setStyle = function(value){
elem.style['left'] = value + 'px'
}
//移动的距离
var now = (end - start) * percent + start;
if(percent === 1){
setStyle(now)
stop();
}else{
setStyle(now)
}
}

//开始执行动画
var timerId = setInterval(tick, 13);
}
</script>

requestAnimationFrame 实现调用了120次左右



<!doctype html><img id="book" style="background:red;opacity:1;position: relative; left: 500px;" alt="" width="100" height="123" data-mce-style="background: red; opacity: 1; position: relative; left: 500px;" /><div id="several"><br /></div><script type="text/javascript">

var book = document.getElementById('book')
var several = document.getElementById('several');

animate(book, {
left: 50,
duration: 2000
})

function animate(elem, options){
//动画初始值
var start = 500
//动画结束值
var end = options.left

var createTime = function(){
return (+new Date)
}
//动画开始时间
var startTime = createTime();

var timerId;

//开始动画
var startAnim = function() {
timerId = requestAnimationFrame(tick,15);
}
//停止动画
var stopAnim = function() {
cancelAnimationFrame(timerId)
}

var i = 0;

function tick(){
i++;
several.innerHTML = 'requestAnimationFrame调用次数:' + i;
//每次变化的时间
var remaining = Math.max(0, startTime + options.duration - createTime())
var temp = remaining / options.duration || 0;
var percent = 1 - temp;
var setStyle = function(value){
elem.style['left'] = value + 'px'
}
//移动的距离
var now = (end - start) * percent + start;
if(percent === 1){
setStyle(now)
stopAnim() ;
}else{
setStyle(now)
startAnim(tick);
}
}

//开始执行动画
startAnim(tick);
}
</script>

通过对比,在同样的时间里,通过定时器刷新的次数是要更多,当然定时器跟设置的时间是有关系的

这里我要强调一点,有效值,就是我们在浏览器能接受的范围内,给出一个最佳的渲染时间,这样才是一个性能优化的最佳的选择

动画requestAnimationFrame的更多相关文章

  1. 移动端动画——requestAnimationFrame

    window.requestAnimationFrame() 告诉浏览器--你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画.该方法需要传入一个回调函数作为参数,该回调函数会 ...

  2. requestAnimationFrame的用法

    该方法用于在浏览器中制作动画.通过递归调用同一方法来不断更新画面以达到动起来的效果,但它优于setTimeout/setInterval的地方在于它是由浏览器专门为动画提供的API,在运行时浏览器会自 ...

  3. h5编写帧动画

    var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame; var ...

  4. H5实现摇一摇技术总结

    摇一摇遇到的问题 一.如何对摇晃效果进行反馈 刚开始的处理方式是,摇晃过程中不做任何处理,但后来反馈说这种效果不好,好像就没有摇动一样,如果声音也不响的话,就真的和什么都没发生一样. 后来想了想,加入 ...

  5. 浏览器-04 WebKit 渲染2

    渲染主循环(main loop)和requestAnimationFrame requestAnimationFrame 使用requestAnimationFrame而非setTimeout/set ...

  6. H5摇一摇遇到的问题

    一.如何对摇晃效果进行反馈 刚开始的处理方式是,摇晃过程中不做任何处理,但后来反馈说这种效果不好,好像就没有摇动一样,如果声音也不响的话,就真的和什么都没发生一样. 后来想了想,加入摇晃过程动画,就像 ...

  7. 【WebGL】《WebGL编程指南》读书笔记——第4章

    一.前言        今天继续第四章的学习内容,开始学习复合变换的知识. 二.正文        Example1: 复合变换 在书中,作者为我们封装了一套用于变换的矩阵对象:Matrix4对象.它 ...

  8. 【带着canvas去流浪(7)】绘制水球图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 四. 文字淹水效果的实现 五. 关于canvas抗锯齿 六. 小结 示例代码托管在:http://www.github.com/dashnowor ...

  9. 浏览器根对象window之操作方法

    1.1 不常用 alert:带有一条指定消息和一个OK按钮的警告框. confirm:带有指定消息和OK及取消按钮的对话框. prompt:可提示用户进行输入的对话框. print:打印网页. ope ...

随机推荐

  1. 关于.NET异常处理的思考

    年关将至,对于大部分程序员来说,马上就可以闲下来一段时间了,然而在这个闲暇的时间里,唯有争论哪门语言更好可以消磨时光,估计最近会有很多关于java与.net的博文出现,我表示要作为一个吃瓜群众,静静的 ...

  2. 可爱的豆子——使用Beans思想让Python代码更易维护

    title: 可爱的豆子--使用Beans思想让Python代码更易维护 toc: false comments: true date: 2016-06-19 21:43:33 tags: [Pyth ...

  3. 常见CSS与HTML使用误区

       误区一.多div症 <div class="nav"> <ul> <li><a href="/home/"> ...

  4. 计算机程序的思维逻辑 (54) - 剖析Collections - 设计模式

    上节我们提到,类Collections中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了第一类,本节我们介绍第二类. 第二类方法大概可以分为两组: 接受其他 ...

  5. ASP.NET 5 RC1 升级 ASP.NET Core 1.0 RC2 记录

    升级文档: Migrating from DNX to .NET Core Migrating from ASP.NET 5 RC1 to ASP.NET Core 1.0 RC2 Migrating ...

  6. html5 与视频

    1.视频支持格式. 有3种视频格式被浏览器广泛支持:.ogg,.mp4,.webm. Theora+Vorbis=.ogg  (Theora:视频编码器,Vorbis:音频编码器) H.264+$$$ ...

  7. python 3.5 成功安装 scrapy 的步骤

    http://www.cnblogs.com/hhh5460/p/5814275.html

  8. 用django创建一个项目

    首先你得安装好python和django,然后配置好环境变量,安装python就不说了,从配置环境变量开始 1.配置环境变量 在我的电脑处点击右键,或者打开 控制面板\系统和安全\系统 -> 左 ...

  9. React Native环境配置之Windows版本搭建

    接近年底了,回想这一年都做了啥,学习了啥,然后突然发现,这一年买了不少书,看是看了,就没有完整看完的.悲催. 然后,最近项目也不是很紧了,所以抽空学习了H5.自学啃书还是很无趣的,虽然Head Fir ...

  10. Linux-Rhel6 恢复误删文件

    需要工具extundelete(可通过xshell上传下载到linux)知识点:ifconifig eth0             查看ipfdisk /dev/sda          管理磁盘m ...