音の鳴るブログ

鳴らないこともある

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() ができた方が良い。