タイマーシリーズ第2編——神器と呼ばれるrequestAnimationFrame

8307 ワード

前の話
settimoutやsetIntervalとは異なり、requestAnimationFrameでは時間間隔を設定する必要はありません.これは何のメリットがありますか?なぜrequestAnimationFrameは神器と呼ばれているのでしょうか?HTML 5に追加されたタイマーrequestAnimationFrameについて詳しく説明します
 
導入
タイマーはjavascriptアニメーションの核心技術である.アニメーションループを作成する鍵は、遅延時間がどれくらい適切かを知ることです.一方、サイクル間隔は十分に短くなければなりません.そうすれば、異なるアニメーション効果がスムーズになります.一方、ループ間隔は、ブラウザが発生した変化をレンダリングできるようにするには、十分な長さが必要です.
ほとんどのコンピュータディスプレイのリフレッシュ周波数は60 Hzで、1秒に60回再描画することに相当します.ほとんどのブラウザでは、ディスプレイの再描画頻度を超えないように、再描画操作を制限しています.その頻度を超えてもユーザー体験は向上しません.したがって、最もスムーズなアニメーションの最適なサイクル間隔は1000 ms/60であり、約16.6 msに等しい.
settimeoutとsetIntervalの問題は、それらが正確ではないことです.これらの内在的な動作メカニズムは、時間間隔パラメータが実際には、ブラウザUIスレッドキューにアニメーションコードを追加して実行を待つ時間を指定するだけであることを決定する.キューの前に他のタスクが追加されている場合は、アニメーションコードは前のタスクが完了してから実行されます.
requestAnimationFrameはシステムの時間間隔を採用し、最適な描画効率を維持し、間隔時間が短すぎるため、過度な描画をもたらし、オーバーヘッドを増加させない.また、間隔が長すぎるため、アニメーションカートンの使用がスムーズではないため、各種のウェブページのアニメーション効果に統一的なリフレッシュメカニズムを持たせることができ、それによってシステム資源を節約し、システム性能を高め、視覚効果を改善することができる.
 
特長
【1】requestAnimationFrameは、フレームごとのすべてのDOM操作を集約し、1回の再描画または還流で完了し、再描画または還流の時間間隔がブラウザのリフレッシュ周波数に追随する
【2】非表示または非表示の要素では、requestAnimationFrameは再描画またはリフローを行わないので、CPU、GPU、メモリの使用量が少なくなることは当然である
【3】requestAnimationFrameは、ブラウザがアニメーション専用に提供するAPIであり、実行時にブラウザがメソッドの呼び出しを自動的に最適化し、ページがアクティブでない場合、アニメーションが自動的に一時停止し、CPUのオーバーヘッドを効果的に節約する
 
使用
requestAnimationFrameの使い方はsettimeoutと似ていますが、時間間隔を設ける必要はありません.requestAnimationFrameは、ブラウザが再描画する前に呼び出されるコールバック関数をパラメータとして使用します.タイマーの番号を示す整数を返します.この値はcancelAnimationFrameに渡され、この関数の実行を取り消すことができます.
requestID = requestAnimationFrame(callback); 
//     1 0
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
console.log(timer);//1

cancelAnimationFrameメソッドタイマーをキャンセルするには
//         
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
cancelAnimationFrame(timer);

戻り値をそのまま使用してキャンセルすることもできます
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
cancelAnimationFrame(1);

 
互換性
IE 9-ブラウザはこの方法をサポートしておらず、settimeoutを使用して互換性がある
【簡易互換性】
if (!window.requestAnimationFrame) {
    requestAnimationFrame = function(fn) {
        setTimeout(fn, 17);
    };    
}

【厳格な互換性】
if(!window.requestAnimationFrame){
    var lastTime = 0;
    window.requestAnimationFrame = function(callback){
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0,16.7-(currTime - lastTime));
        var id  = window.setTimeout(function(){
            callback(currTime + timeToCall);
        },timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    }
}
if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
}

 
適用
setInterval、setTimeout、requestAnimationFrameの3つの方法を使用して、簡単な制度効果を作成します.
【1】setInterval
0%
<span style="color:#0000ff;">var</span><span style="color:#000000;"> timer; btn.onclick </span>= <span style="color:#0000ff;">function</span><span style="color:#000000;">(){ clearInterval(timer); myDiv.style.width </span>= '0'<span style="color:#000000;">; timer </span>= setInterval(<span style="color:#0000ff;">function</span><span style="color:#000000;">(){ </span><span style="color:#0000ff;">if</span>(parseInt(myDiv.style.width) < 500<span style="color:#000000;">){ myDiv.style.width </span>= parseInt(myDiv.style.width) + 5 + 'px'<span style="color:#000000;">; myDiv.innerHTML </span>= parseInt(myDiv.style.width)/5 + '%'; }<span style="color:#0000ff;">else</span><span style="color:#000000;">{ clearInterval(timer); } },</span>16<span style="color:#000000;">); } </span>

【2】setTimeout
0%
<span style="color:#0000ff;">var</span><span style="color:#000000;"> timer; btn.onclick </span>= <span style="color:#0000ff;">function</span><span style="color:#000000;">(){ clearTimeout(timer); myDiv.style.width </span>= '0'<span style="color:#000000;">; timer </span>= setTimeout(<span style="color:#0000ff;">function</span><span style="color:#000000;"> fn(){ </span><span style="color:#0000ff;">if</span>(parseInt(myDiv.style.width) < 500<span style="color:#000000;">){ myDiv.style.width </span>= parseInt(myDiv.style.width) + 5 + 'px'<span style="color:#000000;">; myDiv.innerHTML </span>= parseInt(myDiv.style.width)/5 + '%'; timer = setTimeout(fn,16<span style="color:#000000;">); }</span><span style="color:#0000ff;">else</span><span style="color:#000000;">{ clearTimeout(timer); } },</span>16<span style="color:#000000;">); } </span>

【3】requestAnimationFrame
0%
<span style="color:#0000ff;">var</span><span style="color:#000000;"> timer; btn.onclick </span>= <span style="color:#0000ff;">function</span><span style="color:#000000;">(){ myDiv.style.width </span>= '0'<span style="color:#000000;">; cancelAnimationFrame(timer); timer </span>= requestAnimationFrame(<span style="color:#0000ff;">function</span><span style="color:#000000;"> fn(){ </span><span style="color:#0000ff;">if</span>(parseInt(myDiv.style.width) < 500<span style="color:#000000;">){ myDiv.style.width </span>= parseInt(myDiv.style.width) + 5 + 'px'<span style="color:#000000;">; myDiv.innerHTML </span>= parseInt(myDiv.style.width)/5 + '%'; <span style="color:#000000;"> timer = requestAnimationFrame(fn); }</span><span style="color:#0000ff;">else</span><span style="color:#000000;">{ cancelAnimationFrame(timer); } }); } </span>