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詳解

相關文章
相關標籤/搜索