requestAnimationFrame について学んでみた
この記事は賞味期限切れです。(更新から1年が経過しています)
requestAnimationFrame は、JavaScriptベースのアニメーションの為の比較的新しめの実装です。 今更感たっぷりですが、今回はそれを試しにいじくってみようと思います。
requestAnimationFrame とは
window.requestAnimationFrame – Web API リファレンス | MDN
window.requestAnimationFrame() メソッドは、ブラウザに描画させたいアニメーションを指定し、次の再描画の前に、アニメーションを更新する指定した関数を呼び出すように要求します。このメソッドは再描画する前に呼び出されるコールバックメソッドを引数にひとつとります。
ちょっとわかりにくいですが、 要するに次の再描画のタイミングで処理を実行する事を予約できる setTimeout のような代物だと解釈しています。
var step = function(){
/* アニメーションの処理 */
requestAnimationFrame(step);
};
step();
このように書くと、step内の処理がおよそ60FPSぐらいの頻度で繰り返されます。 つまり、setTimeoutで書きなおすとこんな事をしている事になるのでしょうか。
var timer = null;
var step = function(){
clearTimeout(timer);
/* アニメーションの処理 */
timer = setTimeout(step, 1000 / 60);
};
step();
タイマーとrequestAnimationFrame
挙動としては近しい物なのですが、具体的にこの2つが異なる点はこんな感じなのでしょうか?
- requestAnimationFrame はウィンドウがアクティブでない時にFPSを落とす
- requestAnimationFrame は再描画出来るタイミングで実行されるので、FPSを保証しない
(setTimeoutが必ず保証するという意味ではない) - setTimeoutはなにがなんでも言われた時間に実行しようとする実直なやつ
特に前者の違いはパフォーマンスに結構影響を及ぼしそうです。 非アクティブにしたタブの中でゴリゴリメモリを消費していく… なんていう事が起きにくくなりますね。
タイマーよりアニメーションに適した実装と言えそうです。
ブラウザ対応
気になるブラウザ対応ですが、MDNのリファレンスのサンプルから拝借してきたのが下記のコードです。
(function() {
var requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
}());
問題のIEですが、調べた限りではIE10から “requestAnimationFrame” と “msRequestAnimationFrame” ともに使用可能で、IE9以前は非対応とのことなので、”msRequest〜” のくだりは不要そうですね。
該当箇所を削除して、非常に簡単ではありますが非対応環境用のコードを足してみましょう。
(function(win){
var timer = null, polyfill;
polyfill = function(callback){
clearTimeout(timer);
setTimeout(callback, 1000 / 60);
};
win.requestAnimationFrame = win.requestAnimationFrame
|| win.mozRequestAnimationFrame
|| win.webkitRequestAnimationFrame
|| polyfill;
}(window));
これでどの環境でも「だいたい」同じような動きをするようになると思います。
実際に何か動かしてみる
早速、簡単なデモを動かしてみます。クリックした場所に顔文字が近づいて行きます。
JavaScript(抜粋)
(function(){
var target, $el, step;
target = { left: 0, top: 0 };
$el = $(".sample");
step = function(){
var pos = $el.offset();
$el.css({
left: "+=" + (target.left - pos.left) / 5,
top: "+=" + (target.top - pos.top) / 5
});
requestAnimationFrame(step);
};
step();
$(document).on("click", function(e){
target.left = e.clientX;
target.top = e.clientY;
});
}());
まとめ
requestAnimationFrameは、jQueryでは諸問題があって現在は採用していない様です。
cf) Why doesn’t jQuery use requestAnimationFrame? – Stack Overflow
確かに時間ベースの処理と相性が悪い部分はありそうです。
取り急ぎインターバルで何かを監視したい時などに使ってみるか、 あるいは、$.fn.animate が苦手な部分で活躍してくれるかもしれませんね。
コメント