亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript動畫抖動的原因是什么與怎么解決

發布時間:2022-06-14 14:56:16 來源:億速云 閱讀:176 作者:iii 欄目:開發技術

這篇文章主要講解了“JavaScript動畫抖動的原因是什么與怎么解決”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript動畫抖動的原因是什么與怎么解決”吧!

使用定時器實現動畫出現卡頓的原因

  • 主要原因是瀏覽器無法確定定時器的回調函數的執行時機。以 setInterval 為例,當一個 setInterval 定時器被創建后,它的回調任務會被放到異步隊列,只有當同步任務執行完成后,瀏覽器才會檢查異步隊列中是否有需要執行的異步任務,如果有,就取出執行,這樣會使任務的實際執行時機比所設定的延遲時間要晚一些。

這個問題跟瀏覽器的事件循環機制有關,JavaScript 引擎在解析執行我們的代碼的時候,遇到定時器,會調用瀏覽器 API,讓定時器去進行倒計時,此時并不阻塞同步代碼的執行,當定時器倒計時完畢,定時器回調會被放入宏任務隊列等待執行。

在這個過程中問題就來了,如果說同步代碼的執行需要50ms,而定時器設置的定時只有20ms,那么由于事件循環的機制,還是要等待同步任務執行完整之后再來執行微任務隊列中的定時器回調,而這中間,又相隔了30ms,在這30ms的過程中,定時器的回調一直處于 pendding 的狀態。如果定時器中是動畫相關的操作,那也需要在預期的時間上多等待50ms。

畫了張圖,希望能幫助大家理解(如果不能幫助大家理解,那么請忽略這張圖……)

JavaScript動畫抖動的原因是什么與怎么解決

  • 屏幕分辨率和尺寸也會影響刷新頻率,不同設備的屏幕繪制頻率可能會有所不同,而 setInterval 只能設置一個固定的時間間隔,這個間隔時間不一定與屏幕的刷新時間同步,所以就可能會導致動畫出現隨機丟幀的問題。

這里有兩個點,一個是顯示器的刷新頻率,另一個是定時器的時間間隔。

一般顯示器刷新頻率都是60Hz,這基本上意味著每秒需要重繪60次。大多數瀏覽器都會限制重繪的頻率,使其不超過顯示器的刷新頻率。因為超過刷新頻率,用戶也感知不到,白白浪費性能。

因此,實現平滑動畫最佳的重繪間隔為1000ms/60,大約17毫秒。以這個速度重繪,可以實現最平滑的動畫效果。因為這已經是瀏覽器的重繪頻率的極限了。

知道何時繪制下一幀,是創造平滑動畫的關鍵。直到幾年前,都沒有確切保證讓瀏覽器在何時把下一幀繪制出來的方法。隨著 <canvas>HTML5 游戲的興起,開發者發現 setIntervalsetTimeout 的不精確是個大問題,而瀏覽器自身的計時器也存在著精度不足毫秒的問題。

以下是幾個瀏覽器計時器的精度情況:

  • IE8 以及之前的版本計時器精度為 15.625ms;

  • IE9 及之后的版計時器精度為 4ms;

  • FireFox 和 Safari 的計時器精度約為 10ms;

  • Chrome 的計時器精度為 4ms。

以 Chrome 為例,它的計時器精度為 4ms,這意味著 0~4 之間的任何值最終要么是 0,要么是4;不可能是別的值。因此,即使將瀏覽器的時間間隔設置為最優,也免不了只能得到相近似的結果。

對于 JavaScript 來說,它不知道瀏覽器會在何時發生重繪。因此,我們通過定時器做動畫的時候,在定時器中控制動畫的代碼已經執行完成的情況下,動畫效果并不一定會立馬生效,因為此時瀏覽器可能還處在等待下一次重繪的過程中,當下一次重繪完成,動畫效果才能在瀏覽器窗口中顯示出來。

而由于瀏覽器計時器時間差的問題,會導致定時器的計時并不一定是我們設置的 17 ms,而是在多個時間點內反復橫跳,也因此才出現使用定時器做動畫的時候動畫抖動的問題,在復雜的動畫中,這種問題尤為明顯。

在這樣的環境下,今天的主角 requestAnimationFrame 應運而生!

requestAnimationFrame 的前世今生

Mozilla 的 Robert O'Callahan 一直在思考這個問題,并且提出了一個獨特的解決方案。他指出,瀏覽器知道 CSS 過渡和動畫應該什么時候開始,并且能夠計算出正確的時間間隔,到時間就去刷新用戶界面。

但是對于 JavaScript 而言,瀏覽器并不知道動畫什么時候開始。他給出的方案是創造一個名為 MozRequestAnimationFrame 的新方法,以此來通知瀏覽器某些 JavaScript 代碼要執行動畫了。這樣瀏覽器就可以在運行某些代碼后進行適當的優化。

目前,所有的瀏覽器都支持這個方法不帶前綴的版本,也就是現在用到的 requestAnimationFrame

requestAnimationFrame VS setInterval

這里就不再過多的介紹 requestAnimationFrame 的詳細用法了,它的用法并不復雜。

與定時器不同的是,requestAnimationFrame 只會在被調用的時候執行一次動畫,而不會連續執行。如果想做連續的動畫,則可以通過遞歸來實現對 requestAnimationFrame 的連續調用。

接下來通過一個 demo 來對比一下使用 requestAnimationFramesetInterval 兩者做出來的動畫效果之間的差異。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    .square1,
    .square2 {
      position: absolute;
      width: 100px;
      height: 100px;
    }
    .square1 {
      top: 40px;
      background: red;
    }
    .square2 {
      top: 150px;
      background: blue;
    }
  </style>
  <body>
    <div class="container">
      <div class="square1"></div>
      <div class="square2"></div>
      <button class="btn">開始!</button>
    </div>
    <script>
      const square1El = document.querySelector('.square1')
      const square2El = document.querySelector('.square2')
      // 定時器版
      function squareMove() {
        let timer = null
        square1El.style.left = '0px'
        timer = setInterval(() => {
          const squareLeft = parseInt(square1El.style.left)
          if (squareLeft >= 500) return clearInterval(timer)
          square1El.style.left = squareLeft + 1 + 'px'
        }, 17)
      }

      // requestAnimationFrame 版
      function squareMove2() {
        let timer = null
        square2El.style.left = '0px'

        function updateAnimation() {
          const squareLeft = parseInt(square2El.style.left)
          if (squareLeft >= 500) return cancelAnimationFrame(timer)
          square2El.style.left = squareLeft + 1 + 'px'
          window.requestAnimationFrame(updateAnimation)
        }

        window.requestAnimationFrame(updateAnimation)
      }

      document.querySelector('.btn').addEventListener('click', () => {
        squareMove()
        squareMove2()
      })
    </script>
  </body>
</html>

在頁面中畫了兩個正方形,當點擊按鈕的時候方塊開始運動,紅色方塊是使用 setInterval 實現的動畫,藍色方塊使用的是 requestAnimationFrame

在生成gif的時候視頻被壓縮了,但是還是能看到紅色的方塊在開始運動的時候有明顯的抖動,而藍色的方塊則比較絲滑。

實際上,requestAnimationFrame 的回調函數可以接收一個參數,這個參數是一個 DOMHightResTimeStamp 的實例(比如:performance.now()的返回值),用來表示下一次重繪的時間。這一點非常重要,requestAnimationFrame 實際上是把重繪任務安排在了未來的一個已知的時間點上,而且通過這個參數來告訴開發者。

類似于 setInterval 的清除方法 clearIntervalrequestAnimationFrame 也有對應的取消重繪的方法 cancelAnimationFrame,用法也跟 clearInterval 非常類似,在每次調用 requestAnimationFrame 的時候,都會返回一個id,cancelAnimationFrame 就是通過這個id去取消對應的 requestAnimationFrame

感謝各位的閱讀,以上就是“JavaScript動畫抖動的原因是什么與怎么解決”的內容了,經過本文的學習后,相信大家對JavaScript動畫抖動的原因是什么與怎么解決這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

延吉市| 邮箱| 搜索| 新密市| 浪卡子县| 东明县| 灵山县| 蓝田县| 乌恰县| 乌鲁木齐县| 嘉兴市| 会昌县| 黑河市| 新宾| 蒙山县| 萍乡市| 白山市| 孙吴县| 眉山市| 邯郸县| 临湘市| 皮山县| 济源市| 礼泉县| 阳原县| 宜丰县| 高州市| 平凉市| 乳源| 彰化县| 垦利县| 焦作市| 乐至县| 盐源县| 南川市| 宜都市| 随州市| 扬州市| 乌海市| 铜川市| 鹿邑县|