对动画循环使用 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 问题有一个现场演示