對動畫迴圈使用 requestAnimationFrame() NOT setInterval()

requestAnimationFrame 類似於 setInterval,它具有以下重要改進:

  • 動畫程式碼與顯示重新整理同步以提高效率 clear +重繪程式碼已安排,但未立即執行。只有當顯示準備好重新整理時,瀏覽器才會執行清除+重繪程式碼。與重新整理週期的這種同步通過為程式碼提供最完整的可用時間來提高動畫效能。

  • 在允許另一個迴圈開始之前,每個迴圈始終完成。這可以防止撕裂,即使用者看到圖紙的不完整版本。當撕裂發生時,眼睛特別注意撕裂並分散注意力。因此,防止撕裂會使動畫看起來更流暢,更加一致。

  • 當使用者切換到其他瀏覽器選項卡時,動畫會自動停止。這節省了移動裝置的功率,因為​​裝置不會浪費能力來計算使用者當前無法看到的動畫。

裝置顯示每秒重新整理大約 60 次,因此 requestAnimationFrame 可以每秒大約 60連續重繪。眼睛以每秒 20-30 幀的速度運動,因此 requestAnimationFrame 可以輕鬆建立運動的幻覺。

請注意,在每個 animateCircle 的末尾都會呼叫 requestAnimationFrame。這是因為每個’requestAnimatonFrameonly 請求單個執行動畫功能。

示例:簡單`requestAnimationFrame

<!doctype html>
<html>
<head>
<style>
    body{ background-color:white; }
    #canvas{border:1px solid red; }
</style>
<script>
window.onload=(function(){

    // canvas related variables
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
           
    // start the animation
    requestAnimationFrame(animate);

    function animate(currentTime){

        // draw a full randomly circle
        var x=Math.random()*canvas.width;
        var y=Math.random()*canvas.height;
        var radius=10+Math.random()*15;
        ctx.beginPath();
        ctx.arc(x,y,radius,0,Math.PI*2);
        ctx.fillStyle='#'+Math.floor(Math.random()*16777215).toString(16);
        ctx.fill();

        // request another loop of animation
        requestAnimationFrame(animate);
    }

}); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=512 height=512></canvas>
</body>
</html>

為了說明 requestAnimationFrame 的優點,這個 stackoverflow 問題有一個現場演示