【面试】JS实现动画之setTimeout、setInterval和requestAnimationFrame

参考:《JS高级程序设计》,这篇requestAnimationFrame文章

JS实现动画主要有三种方式:setTimeoutsetIntervalrequestAnimationFrame。其中最后一种方法比较好。

setTimeoutsetInterval

setTimeoutsetInterval可以用来创建定时器。定时器对队列的工作方式是,当特定时间过去后将代码插入。

定时器指定的时间间隔表示何时将定时器的代码添加到队列,而不是何时实际执行代码!

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确保了定时器代码规则地插入队列中(注意不是规则的执行)。

当定时器代码要插入队列时,已经有一个定时器代码 正在运行,并且有一个 定时器实例 在等待,则此处不插入,跳过。 确保定时器代码加入到队列中的最小时间间隔为指定间隔(实际间隔有可能大于指定间隔)。

缺点:

  • 某些间隔被跳过
  • 多个定时器代码执行之间的间隔可能比预期的小

setTimeout

调用链式setTimeout可以避免上述两个缺点,每次函数执行的时候都会创建换一个新的定时器。在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何确实的间隔。并且确保在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。

一个用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开销

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值