JSタイマー三種盛りとそのインターフェース
最近タイマーAPIを書くブームが来ていて、とりあえず3つほど書いたので順番に紹介していきます。
ブラウザのタイマーはタブの裏に入ると精度が悪くなる。それを解消する方法として WebWorker でタイマーを作動させてメッセージ送信→コールバック関数を実行するやり方がある。ウェブオーディオとか見えなくてもちゃんと処理してほしい時に使える。
setInterval で 100 を指定すると、だいたい 100ms 単位でコールバック関数が呼ばれるのだけど、これは 100ms ± 10% くらいのアバウトな間隔でコールバックされるやつ。"酔う"感じとかは設定で変えられる。
sinon の FakeTimer などのように、手動で時間を進められるやつ。テストに使う。
いずれもネイティブと同じインターフェースで setInterval
とか setTimeout
を呼んで使う。例えば、n回タイマー処理をしたい場合、以下のようなインターフェースにしておくと、状況に応じてタイマーを切り替えられるという算段です。
var nTimesInterval = (n, callback, delay, timerAPI = global) => { var count = 0; var timerId = timerAPI.setInterval(() => { callback(count++); if (count >= n) { timerAPI.clearInterval(timerId); } }, delay); }; // 普通のとき nTimesInterval(10, callback, 100); // バックグラウンドでも絶対に実行したいとき nTimesInterval(10, callback, 100, WorkerTimer); // ぐだぐだな感じにしたいとき nTimesInterval(10, callback, 100, DrunkTimer); // テストのとき nTimesInterval(10, callback, 100, TickableTimer);
APIを引数で受け取ると良いというのは前回書いた記事と同じ。
新しいタイマーを作るぞ!というときにオブジェクティブな感じで new して start / stop みたいなインターフェースにするのではなくて、ネイティブのに合わせておくと使用性が上がる。
具体的には関数名を同じにするのと、出来たらメソッドでなくて関数にする。例えば乱数を生成するのは Math.random
と同じように random
という名前でアクセスできて、fn = foo.random; fn()
ができた方が良い。