前言
与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.
大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms.
而setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行.
requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果.
特点
  【1】requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
  【2】在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
  【3】requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下(不是当前页)的话,动画会自动暂停,有效节省了CPU开销
  
特别提醒:
requestAnimationFrame是在主线程上完成。这意味着,如果主线程非常繁忙,requestAnimationFrame的动画效果会大打折扣。
基本用法
| 1
 | requestID = window.requestAnimationFrame(callback);
 | 
cancelAnimationFrame方法用于取消重绘。
| 1
 | window.cancelAnimationFrame(requestID);
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | (function() {var lastTime = 0;
 var vendors = ['webkit', 'moz'];
 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
 window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
 window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
 window[vendors[x] + 'CancelRequestAnimationFrame'];
 }
 
 if (!window.requestAnimationFrame) {
 window.requestAnimationFrame = function(callback, element) {
 var currTime = new Date().getTime();
 var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
 var id = window.setTimeout(function() {
 callback(currTime + timeToCall);
 }, timeToCall);
 lastTime = currTime + timeToCall;
 return id;
 };
 }
 if (!window.cancelAnimationFrame) {
 window.cancelAnimationFrame = function(id) {
 clearTimeout(id);
 };
 }
 }());
 
 | 
一个简单的进度条代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | var ele = document.getElementById("test");var progress = 0;
 
 function step(timestamp) {
 console.log('回调队列被触发的时间-------' + timestamp);
 progress += 1;
 ele.style.width = progress + "%";
 ele.innerHTML = progress + "%";
 if (progress < 100) {
 requestAnimationFrame(step);
 } else {
 cancelAnimationFrame(timer);
 }
 }
 var timer = requestAnimationFrame(step);
 document.getElementById("run").addEventListener("click", function() {
 ele.style.width = "1px";
 progress = 0;
 requestAnimationFrame(step);
 }, false);
 
 | 
demo连接:飞机票