前言

在研究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 资源

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

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

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 核心技术

window.requestNextAnimationFrame = (function () {
var originalWebkitRequestAnimationFrame = undefined,
wrapper = undefined,
callback = undefined,
geckoVersion = ,
userAgent = navigator.userAgent,
index = ,
self = this; // Workaround for Chrome 10 bug where Chrome
// does not pass the time to the animation function if (window.webkitRequestAnimationFrame) {
// Define the wrapper wrapper = function (time) {
if (time === undefined) {
time = +new Date();
}
self.callback(time);
}; // Make the switch originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame; window.webkitRequestAnimationFrame = function (callback, element) {
self.callback = callback; // Browser calls the wrapper and wrapper calls the callback originalWebkitRequestAnimationFrame(wrapper, element);
}
} // Workaround for Gecko 2.0, which has a bug in
// mozRequestAnimationFrame() that restricts animations
// to 30-40 fps. if (window.mozRequestAnimationFrame) {
// Check the Gecko version. Gecko is used by browsers
// other than Firefox. Gecko 2.0 corresponds to
// Firefox 4.0. index = userAgent.indexOf('rv:'); if (userAgent.indexOf('Gecko') != -) {
geckoVersion = userAgent.substr(index + , ); if (geckoVersion === '2.0') {
// Forces the return statement to fall through
// to the setTimeout() function. window.mozRequestAnimationFrame = undefined;
}
}
} return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame || function (callback, element) {
var start,
finish; window.setTimeout(function () {
start = +new Date();
callback(start);
finish = +new Date(); self.timeout = / - (finish - start); }, self.timeout);
};
}()); window.cancelNextRequestAnimationFrame = window.cancelRequestAnimationFrame
|| window.webkitCancelAnimationFrame
|| window.webkitCancelRequestAnimationFrame
|| window.mozCancelRequestAnimationFrame
|| window.oCancelRequestAnimationFrame
|| window.msCancelRequestAnimationFrame
|| 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. 创建 OVS flat network - 每天5分钟玩转 OpenStack(134)

    上一节完成了 flat 的配置工作,今天创建 OVS flat network.Admin -> Networks,点击 "Create Network" 按钮. 显示创建页 ...

  2. 首个threejs项目-前端填坑指南

    第一次使用threejs到实际项目中,开始的时候心情有点小激动,毕竟是第一次嘛,然而做着做着就感受到这玩意水好深,满满的都是坑,填都填不过来.经过老板20天惨无人道的摧残,终于小有成就. 因为第一次搞 ...

  3. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  4. OpenCASCADE BRep Projection

    OpenCASCADE BRep Projection eryar@163.com 一网友发邮件问我下图所示的效果如何在OpenCASCADE中实现,我的想法是先构造出螺旋线,再将螺旋线投影到面上. ...

  5. 深入理解MySql子查询IN的执行和优化

    IN为什么慢? 在应用程序中使用子查询后,SQL语句的查询性能变得非常糟糕.例如: SELECT driver_id FROM driver where driver_id in (SELECT dr ...

  6. 创建 OVS Local Network - 每天5分钟玩转 OpenStack(129)

    上一节我们完成了 OVS 的准备工作,本节从最基础的 local network 开始学习.local network 不会与宿主机的任何物理网卡连接,流量只被限制在宿主机内,同时也不关联任何的 VL ...

  7. [C#] 简单的 Helper 封装 -- RegularExpressionHelper

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. 在Linux系统下运行微信Web开发者工具

    微信Web开发者工具只有window版本和mac版本,如果想要在Linux系统下运行微信Web开发者工具,需要花费很大周折. 注:带 * 的步骤或文件为不确定是否管用的步骤或文件.本人系统为Linux ...

  9. win10上部署Hadoop-2.7.3——非Cygwin、非虚拟机

    开始接触Hadoop,听人说一般都是在Lunix下部署Hadoop,但是本人Lunix不是很了解,所以Google以下如何在Win10下安装Hadoop(之后再在Lunix下弄),找到不少文章,以下是 ...

  10. Android SDK 与API版本对应关系

    Android SDK版本号 与 API Level 对应关系如下表: Code name Version API level   (no code name) 1.0 API level 1   ( ...