天天看點

requestAnimationFrame和requestIdleCallback

傳統的javascript 動畫是通過定時器 setTimeout 或者 setInterval 實作的。但是定時器動畫一直存在兩個問題
  • 第一個就是動畫的循時間環間隔不好确定,設定長了動畫顯得不夠平滑流暢,設定短了浏覽器的重繪頻率會達到瓶頸,推薦的最佳循環間隔是16.7ms(大多數電腦的顯示器重新整理頻率是60Hz,1000ms/60);
  • 第二個問題是定時器第二個時間參數隻是指定了多久後将動畫任務添加到浏覽器的UI線程隊列中,如果UI線程處于忙碌狀态,那麼動畫不會立刻執行。為了解決這些問題,H5 中加入了 requestAnimationFrame以及requestIdleCallback

1. requestAnimationFrame 會把每一幀中的所有 DOM 操作集中起來,在一次重繪或回流中就完成,并且重繪或回流的時間間隔緊緊跟随浏覽器的重新整理頻率

2. 在隐藏或不可見的元素中,requestAnimationFrame 将不會進行重繪或回流,這當然就意味着更少的 CPU、GPU 和記憶體使用量

3. requestAnimationFrame 是由浏覽器專門為動畫提供的 API,在運作時浏覽器會自動優化方法的調用,并且如果頁面不是激活狀态下的話,動畫會自動暫停,有效節省了 CPU 開銷

requestAnimationFrame的回調會在每一幀确定執行,屬于高優先級任務,而requestIdleCallback的回調則不一定,屬于低優先級任務。

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop() {
        render();
        window.requestAnimationFrame(animloop);
    })();

</script>
</body>
</html>           
requestAnimationFrame預設傳回一個id,cancelAnimationFrame隻需要傳入這個id就可以停止
<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
    var rafId = null


    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }

  
    (function animloop(time) {
        console.log(time,Date.now())
        render();
        rafId = requestAnimationFrame(animloop);
        //如果left等于50 停止動畫
        if(left == 50){
            cancelAnimationFrame(rafId)
        }
    })();

   
</script>
</body>
</html>           

繼續閱讀