🧊

いまさらrequestAnimationFrameを理解する

理解できたらいいな・・。
だいぶ今さら感はあるのですが、改めて知っておきたいタイミングなので。

参考:window.requestAnimationFrame - Web API リファレンス | MDN

一定間隔で処理を繰り返す

CanvasでもCssアニメーションでも、「描画処理を繰り返し実行する」ところは一緒。
そこをどうやって実装するかという話で、今まではsetIntervalやsetTimeoutを再帰で呼んだりしてました。

setInterval

var anim = function() { console.log('Animations here.'); };

window.setInterval(anim, 1000);

一番わかりやすいし手軽です。
だいたいいつもコレなんじゃないでしょうか。

setTimeout

var anim = function() { console.log('Animations here.'); };

(function animLoop(){
  anim();
  window.setTimeout(animLoop, 1000);
}());

setTimeoutだけでも一定間隔での実行は可能です。
ただちょっとわかりにくいですね・・。

requestAnimationFrame

var anim = function() { console.log('Animations here.'); };

(function animloop(){
  anim();
  window.requestAnimationFrame(animloop);
}());

記述としては、setTimeoutとほぼ同じです。
違うところは、実行間隔を指定する引数がないところ。

記述は似ているものの、全然違うところがあります。
実行間隔が指定できないあたり、もうピンときてるかもですが・・。

実行間隔はブラウザまかせ

そうなんです。

MDNによると、

この再描画はフォアグラウンドのタブでおよそ毎秒60回行われるとされています。
しかし、バックグラウンドのタブではより少ない割合に減らされるでしょう。

ようは、厳密な実行間隔は指定できないものの、

  • 毎秒"およそ"60回(60FPSで)実行される
  • ブラウザの負荷にあわせて、描画準備ができ次第、適宜実行される
  • ブラウザがアクティブでない間は、実行回数が自動で低下されメモリ節約

あらためてコードを並べて載せておくと、

var anim = function() { console.log('Animations here.'); };

// 1. setInterval
window.setInterval(anim, 1000 / 60);

// 2. setTimeout
(function animLoop(){
  anim();
  window.setTimeout(animLoop, 1000 / 60);
}());

//3. requestAnimationFrame
(function animloop(){
  anim();
  window.requestAnimationFrame(animloop);
}());


以上の3つは、だいたい同じ結果になるということ。
だいたい。

実用的なのか

まずは世間の状況を。

ブラウザの対応状況

参考:Can I use... Support tables for HTML5, CSS3, etc

私めの主戦場、スマートフォンという名のモバイル環境はと言いますと、

  • Androidは4.xだろうとお構いなく全滅
  • iOSは6.x以降は対応(6.xは要プレフィックス)

iPhone5sさまのおかげでiOS7がどばっと増えることが予想できるので、まぁナシではないかな・・。
にしてもAndroidはもう・・。

というわけで

個人の意見にはなりますが、全然使えるところでは使って良いと思ってます。
"そこまで厳密に実行間隔を意識しなくてもよい"のであれば、setIntervalやsetTimeoutの代わりに使うべきなのかなーと。

もちろん、コードを書く上での制約も生まれます。

  • setIntervalは記述が若干異なるため使えない
  • iOS6以降しか恩恵を受けられない

ここは事前のお約束なのかなーとも。

おまけ

実際に使う場合のコードサンプルとかメモとかそういうの。

定義するとこ

(function (w, r) {
	w['r'+r] = w['r'+r] || w['webkitR'+r] || w['mozR'+r] || w['msR'+r] || w['oR'+r] || function(c){ w.setTimeout(c, 1000 / 60); };
})(window, 'equestAnimationFrame');

これはこちらのスライドから拝借したスニペットですが、スッキリ書けて良いですね。

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

アニメーションのとこ

2秒に一回実行したい処理の場合は、

var interval = 2000,
anim = (function(){

  var i = 0,
  timing = interval / 1000 * 60;

  return function() {
    if (i % timing === 0) {
    console.log('Animations here.' + i);
    }
    i++; 
  };
}());

(function animloop(){
  anim();
  window.requestAnimationFrame(animloop);
}());

FPS前提に慣れてない身としては、こういう風にしないと使えないのです・・。

もっとも、正確にやる必要のある場合は、以下リンクみたくするのがいいのかしら。

参考:requestAnimationFrame でフレームと再描画更新を制御する

この分野の最前と自分との差が半年以上ってところがグッとくるわねー。