在web动画、app动画中,我们经常通过setInterval或setTimeout定时修改DOM、CSS实现动画,如下面代码所示。
var timer=setInterval(function(){
//一些动画
},1000/60)
//清除动画
clearInterval(timer);
不过如此动画的方式极为耗费资源,经常是这样的结果,刚开始比较流畅,5分钟之后动画就卡住了。
浏览器中动画有两种实现形式:通过申明元素实现(如SVG中的元素)和脚本实现。
可以通过setTimeout和setInterval方法来在脚本中实现动画,但是这样效果可能不够流畅,且会占用额外的资源。可参考《Html5 Canvas核心技术》中的论述:
它们有如下的特征:
1、即使向其传递毫秒为单位的参数,它们也不能达到ms的准确性。这是因为javascript是单线程的,可能会发生阻塞。
2、没有对调用动画的循环机制进行优化。
3、没有考虑到绘制动画的最佳时机,只是一味地以某个大致的事件间隔来调用循环。
其实,使用setInterval或setTimeout来实现主循环,根本错误就在于它们抽象等级不符合要求。我们想让浏览器执行的是一套可以控制各种细节的api,实现如“最优帧速率”、“选择绘制下一帧的最佳时机”等功能。但是如果使用它们的话,这些具体的细节就必须由开发者自己来完成。
requestAnimationFrame不需要使用者指定循环间隔时间,浏览器会基于当前页面是否可见、CPU的负荷情况等来自行决定最佳的帧速率,从而更合理地使用CPU。
简介
2011年左右,Paul Irish的《requestAnimationFrame for Smart Animating》首先介绍了requestAnimationFrame的使用,然后经过大家的努力《Timing control for script-based animations》在2013年成为了w3c的候选标准。
requestAnimationFrame的方式的优势如下:
1.经过浏览器优化,动画更流畅
2.窗口没激活时,动画将停止,省计算资源
3.更省电,尤其是对移动终端
requestAnimationFrame的使用方式,简单调用代码如下。function animate() {
// Do whatever
requestAnimationFrame(animate);
// Do something animate
}
//go->
requestAnimationFrame(animate);
有的时候我们必须要加一些控制, requestAnimationFrame也可以像setInterval一样返回一个句柄,然后我们可以取消它。控制动画代码如下。
var globalID;
function animate() {
// Do whatever
globalID=requestAnimationFrame(animate);
// Do something animate
}
//when ot start
globalID=requestAnimationFrame(animate);
//when to stop
cancelAnimationFrame(globalID);
桌面端除了万恶的IE系列低版本9-,移动端除了Opera Mini和Android Browser4.3-其他都支持。总支持率83.38%,不加前缀支持率81.98%,支持率不错。
补丁
Paul Irish的简化版的补丁,补丁和使用如下代码所示。
// 补丁
window.requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
// 使用
(function animate(){
requestAnimationFrame(animate);
//动画
})();