requestAnimationFrame,终结定时器动画时代!

前言

风和日丽,饶有兴致,翻开以前写的一个简单的动画插件,发现是用定时器写的,可是做为有追求的前端,一个问题怎么能有一种解决方案呢?故而,遍寻资料,终于看见曙光,让我查到了requestAnimationFrame 这个宿主对象的方法,也能能优雅的实现js动画!css

传统动画实现

在咱们前端的传统中,在古老的ie称霸的年代,咱们想要实现动画,必需要借助setTimeout或setInterval这两个函数,下面咱们来思考一个问题:html

咱们让一个数字从0开始逐渐变大,到达100时在逐渐变小,如此往复 前端

那么,传统的定时器的写法应该怎么写呢?废话少说上代码html5

//css部分
<style>
      #a {
        font-size: 30px;
      }
    </style>
复制代码
//html部分
<div id="a"></div>
复制代码
//js部分
 var e = document.getElementById("a");
      var flag = true;
      var left = 0;

      function render() {
        if (flag == true) {
          if (left >= 100) {
            flag = false;
          }
          e.innerHTML = left++;
        } else {
          if (left <= 0) {
            flag = true;
          }
          e.innerHTML = left--;
        }
      }
      setInterval(function () {
        render();
      }, 1000/60);
复制代码

以上写法即可以实现循环往复的变大变小的操做!浏览器

这种方法,可行吗?固然可行,完美吗?也还算完美,当忽然发现新大陆之后,定时器便完全被终结了,就好比,你用了苹果的Retina屏幕之后,发现再也回不去了是一个道理,你说1080p的屏幕完美吗?挺完美的,然而当你拿到Retina之后,直呼真香!bash

window.requestAnimationFrame

在了解requestAnimationFrame以前,咱们先来了解几个概念,阐述一下为啥requestAnimationFrame真香markdown

什么是屏幕刷新率

之因此咱们能看到动画,一些动画效果,彻底时由咱们的显示器在短期内不断播放一张张图片,当播放速率过快时,便造成了动画效果,而咱们的显示器在播放图片时,通常有一个播放的频率标准,咱们叫作屏幕刷新率,即图像在屏幕上更新的速度,也即屏幕上的图像每秒钟出现的次数,它的单位是赫兹(Hz)。通常状况下,当刷新率达到60hz基本咱们的肉眼就感受不到他是静态的了,变成了一个连贯的动画!异步

那你可知这是为何呢?函数

为何你感受不到这个变化? 那是由于人的眼睛有视觉停留效应,即前一副画面留在大脑的印象还没消失,紧接着后一副画面就跟上来了,这中间只间隔了16.7ms(1000/60≈16.7), 因此会让你误觉得屏幕上的图像是静止不动的。而屏幕给你的这种感受是对的,试想一下,若是刷新频率变成1次/秒,屏幕上的图像就会出现严重的闪烁,这样就很容易引发眼睛疲劳、酸痛和头晕目眩等症状。(跟主题没啥关系,强行科普一波)oop

动画原理

因为高刷新率的存在,加上人眼睛的视觉停留效应,理解动画的原理就变得很是简单了。 画本质就是要让人眼看到图像被刷新而引发变化的视觉效果,这个变化要以连贯的、平滑的方式进行过渡。,若是一来,在咱们的浏览器,中就能看到连贯的动画效果

定时器的缺点

上面的讲述你应该已经大概知道定时器能实现动画效果了,其实他就是经过不断改变这个元素的位置或者值,来达到快速播放静图片的效果,从而造成一个完整的动画

然而因为定时器的在js中的执行方式,致使它有一些小小的瑕疵,虽然能够忍受,可是有更好的东西出来,为啥不淘汰掉他呢?

咱们知道定时器的执行时间并非肯定的。这是因为js是个单线程的语言,他必须使用异步,来解决一些须要延时执行这个问题,那么为何说定时器的执行时间不是肯定的呢?那就得来细数一下轮询了

Event Loop

Event Loop的是计算机系统的一种运行机制。JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。

在JavaScript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)。

常见的宏任务有:script所有代码、setTimeout、setInterval、setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)、I/O、UI Rendering。

常见的微任务有:Process.nextTick(Node独有)、Promise、Object.observe(废弃)、MutationObserver

下面来简单学习一下Event Loop的执行过程

首先Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),全部的任务都会被放到调用栈等待主线程执行。 JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。 而后,当执行宏任务时,碰见定时器,那么便给定时器中的内容压入队列中,到下一次的Event Loop执行,接着去执行,微任务

最后,微任务执行完毕,清空执行栈,拿到队列中的下一次Event Loop的内容,在开始执行,走到这里,你会发现,在定时器执行的时候,前面还有会一堆同步代码也须要时间,若是前面有个循环个三五百次的话,会很是浪费时间,这就暴露出了定时器的一个缺点:丢帧现象,就是每次间隔实际上是不肯定的,致使跟浏览器的刷刷新率匹配不上,有可能出现的丢帧现象!(后通过大佬更正,定时器丢帧的缘由仅仅是没有被浏览器的策略干涉,并非会被同步任务阻塞)

//这段代码能够证明
  requestAnimationFrame(() => console.log("Hello World"));
      while (true);
   
复制代码

看完流程之后,请仔细参悟上图,会有收获的!

requestAnimationFrame是个啥?

requestAnimationFrame是html5 提供的一个专门用于请求动画的API,顾名思义就是请求动画帧,他被封装在宿主对象中, window.requestAnimationFrame() 告诉浏览器——你但愿执行一个动画,而且要求浏览器在下次重绘以前调用指定的回调函数更新动画。该方法须要传入一个回调函数做为参数,该回调函数会在浏览器下一次重绘以前执行

requestAnimationFrame的优点是啥?

  • 一、requestAnimationFrame 会把每一帧中的全部DOM操做集中起来,在一次重绘或回流中就完成,而且重绘或回流的时间间隔牢牢跟随浏览器的刷新频率,通常来讲,这个频率为每秒60帧。
  • 二、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这固然就意味着更少的的cpu,gpu和内存使用量。

那requestAnimationFrame怎么使用呢?

//html
  <div id="a"></div>
  //js
    <script>
      var e = document.getElementById("a");
      var flag = true;
      var left = 0;

      function render() {
        if (flag == true) {
          if (left >= 100) {
            flag = false;
          }
          e.innerHTML = left++;
        } else {
          if (left <= 0) {
            flag = true;
          }
          e.innerHTML = left--;
        }
      }
      // setInterval(function () {
      //   render();
      // }, 1000);
      (function animloop() {
        render();
        var a=window.requestAnimationFrame(animloop);
      })();
复制代码

到这里就能够结束了,可是忽然有冒出来个疑问,他怎么中止呢?

执行函数放回一个id是回调列表中惟一的标识。是个非零值,没别的意义。你能够传这个值给 window.cancelAnimationFrame() 以取消回调函数。

window.cancelAnimationFrame(a)//注意这个要写在函数体内部,
复制代码

总结

到这里,基本就结束了requestAnimationFrame的探索,因为我也是边学边写,不对之处,请大佬指正!

鸣谢巨人: 深刻理解 requestAnimationFrame requestAnimationFrame详解

相关文章
相关标签/搜索