おいキミ、彼はいったいどこで!?
おいキミ、彼はいったいどこで!?
2014.11.18

アニメーションを実装するなら知っておきたい「requestAnimationFrame」の使い方

おじいちゃん

こんにちは、フロントエンドエンジニアのおじいちゃんです。

今回はパフォーマンスを意識したアニメーションを実装できる「requestAnimationFrame」について書きたいと思います。

requestAnimationFrameとは

requestAnimationFrameは、アニメーション実装時など、再描画が頻繁に行われる処理に使えるメソッドになります。

window.requestAnimationFrame() メソッドは、ブラウザに描画させたいアニメーションを指定し、次の再描画の前に、アニメーションを更新する指定した関数を呼び出すように要求します。このメソッドは再描画する前に呼び出されるコールバックメソッドを引数にひとつとります。
引用元:MDN

setTimeoutやsetIntevalと比較されることが多いですが、主に以下のような違いがあります。

requestAnimationFrameの特徴
  • ブラウザの描画更新単位と同じ単位で呼び出される
  • 次の再描画が行われる前に次のアニメーションをする関数を呼び出す
  • タブが非アクティブの時はFPSを落とす
setInteval、setTimeoutの特徴
  • ブラウザで準備ができていなくても必ず実行
  • タブが非アクティブの状態でも常に実行

これだけを見ると「setTimeoutやsetIntevalでもいいのでは?」と思われるかもしれません。

しかし、setTimeoutやsetIntevalはタブが非アクティブの状態でも動き続けるため、使い方によってはメモリリークの原因となります。
その点、requestAnimationFrameは非アクティブの状態だとFPSを落とすようになっており、メモリの消費を抑えることができます。

requestAnimationFrameの使い方

まずはrequestAnimationFrameを多くのブラウザで利用するために、prefixの記載が必要になります。

(function() {
    var requestAnimationFrame = window.requestAnimationFrame || 
                   window.mozRequestAnimationFrame ||
                               window.webkitRequestAnimationFrame || 
                   window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
})();

requestAnimationFrameの対応状況は以下のようになります。

requestAnimationFrame対応表

参照元:can i use

 
requestAnimationFrameの基本的な使い方は下記のようになります。

(function loop(){
    window.requestAnimationFrame(loop);
    //再描画時の処理
})();

setTimeoutやsetIntevalはタイマーなのでミリ秒を指定しますが、requestAnimationFrameにはミリ秒指定がありません。

冒頭に記載があるのですが、requestAnimationFrameはブラウザの再描画の準備が整ったら次の関数を読み込みます。
読み込む速度はブラウザに依存しているため、一定間隔でアニメーションさせたい場合には使いにくくなってしまいます。

そんなときはDate.getTime() などを使い、requestAnimationFrameに経過時間を取得する処理を追記してあげます。

requestAnimationFrameを用いて経過時間を知るのは下記のようになります。

var startTime = new Date().getTime(); //描画開始時刻を取得
(function loop(){
    window.requestAnimationFrame(loop);
    var currentTime = new Date().getTime(); //経過時刻を取得
    var status = (startTime - currentTime) // 描画開始時刻から経過時刻を引く
    console.log(status);
})();

経過時間から対応するフレームを求める方法は、下記でわかりやすく説明されていますのでご参照ください。

参考:requestAnimationFrame でフレームと再描画更新を制御する – よもつネット

cancelAnimationFrame

requestAnimationFrameを止めたい場合はcancelAnimationFrameを使います。

まずrequestAnimationFrameと同じくprefixを記載してあげます。

(function() {
    var cancelAnimationFrame = window.cancelAnimationFrame || 
                   window.mozcancelAnimationFrame ||
                               window.webkitcancelAnimationFrame || 
                   window.mscancelAnimationFrame;
    window.cancelAnimationFrame = cancelAnimationFrame;
})();

requestAnimationFrameの戻り値をcancelAnimationFrameに渡すことで、止めることができます。

var startTime = new Date().getTime(); //描画開始時刻を取得
(function loop(){
    var requestId = window.requestAnimationFrame(loop); //戻り値を取得
    var currentTime = new Date().getTime(); //経過時刻を取得
    var status = (startTime - currentTime) // 描画開始時刻から経過時刻を引く
    console.log(status);
    
    window.cancelAnimationFrame(requestId); //戻り値をcancelAnimationFrameに渡してあげる
})();

jQueryと併用する場合の注意点

requestAnimationFrameですが、jQueryでサポートされていません。
下記記事でその問題点について挙げられているのでご参照ください。

参考:jQueryで破棄されたrequestAnimationFrameとJSでのアニメーション実装で注意すること

まとめ

いかがでしたでしょうか。

requestAnimationFrameの基本的な使い方は以上になります。requestAnimationFrameを使い、パフォーマンスを意識したアニメーションを実装してみてください。

それでは、お元気で。