参考:《JS高级程序设计》,这篇requestAnimationFrame文章javascript
JS实现动画主要有三种方式:setTimeout
、setInterval
和 requestAnimationFrame
。其中最后一种方法比较好。html
setTimeout
、setInterval
setTimeout
、setInterval
能够用来建立定时器。定时器对队列的工做方式是,当特定时间过去后将代码插入。java
定时器指定的时间间隔表示什么时候将定时器的代码添加到队列,而不是什么时候实际执行代码!浏览器
setInterval
一个用setInterval
实现的进度条例子函数
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script> var timer; btn.onclick = function(){ // 取消对应的定时器,注意与clearTimeout不同 clearInterval(timer); // 注意是字符串,给parseInt用 myDiv.style.width = '0'; timer = setInterval(function(){ // parseInt解析一个字符串,返回一个整数 if(parseInt(myDiv.style.width) < 500){ myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px'; // 总长500,除以5的数字正好是百分比 myDiv.innerHTML = parseInt(myDiv.style.width)/5 + '%'; }else{ clearInterval(timer); } },16); } </script>
复制代码
setInterval
确保了定时器代码规则地插入队列中(注意不是规则的执行)。优化
当定时器代码要插入队列时,已经有一个定时器代码 正在运行,而且有一个 定时器实例 在等待,则此处不插入,跳过。 确保定时器代码加入到队列中的最小时间间隔为指定间隔(实际间隔有可能大于指定间隔)。动画
缺点:ui
setTimeout
调用链式setTimeout
能够避免上述两个缺点,每次函数执行的时候都会建立换一个新的定时器。在前一个定时器代码执行完以前,不会向队列插入新的定时器代码,确保不会有任何确实的间隔。而且确保在下一次定时器代码执行以前,至少要等待指定的间隔,避免了连续的运行。spa
一个用setTimeout
实现进度条的例子设计
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script> var timer; btn.onclick = function() { // 注意与clearInterval不同 clearTimeout(timer); myDiv.style.width = '0'; // 给function取个名字后面链式用 timer = setTimeout(function fn(){ if(parseInt(myDiv.style.width) < 500) { myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px'; myDiv.innerHTML = parseInt(myDiv.style.width)/5 + '%'; // 链式setTimeout timer = setTimeout(fn,16); } else { clearTimeout(timer); } },16) } </script>
复制代码
requestAnimationFrame
用requestAnimationFrame
实现的进度条例子
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script> var timer; btn.onclick = function(){ // 注意cancelAnimationFrame cancelAnimationFrame(timer); myDiv.style.width = '0'; timer = requestAnimationFrame(function fn(){ if(parseInt(myDiv.style.width) < 500) { myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px'; myDiv.innerHTML = parseInt(myDiv.style.width)/5 + '%'; // requestAnimationFrame只传入一个参数 timer = requestAnimationFrame(fn); } else { cancelAnimationFrame(timer); } }) // 只传入一个参数 } </script>
复制代码
【1】requestAnimationFrame会把每一帧中的全部DOM操做集中起来,在一次重绘或回流中就完成,而且重绘或回流的时间间隔牢牢跟随浏览器的刷新频率
【2】在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这固然就意味着更少的CPU、GPU和内存使用量
【3】requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,而且若是页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销