今までsetTimeoutの遅延時間は長くても数十秒程度までしか指定したことがありませんでした。
先日、長時間のタイマー処理がうまく動作しないケースがあったのでご紹介させていただきます。
初めに書いたコード
「15分後に実行する」という処理をする際、普通に考えると以下のように書いてしまいます。
setTimeout(() => {
/* なにか */
/* 素敵なことを */
/* 行なう */
}, 15 * 60 * 1000);
このコードはうまく動きそうですが、実は落とし穴がありました。
スマホもPCも操作しないで放置すると、省電力のためスリープモードになりますよね。
そう、スリープ中はタイマーが止まる1んです。
なので、タイマーが完了するのは開始から30分後かもしれないし、2時間後や翌朝になってしまう場合もあります。
スリープ対策を入れる
今回はそうなってしまうと困る案件だったので、setIntervalで「開始から15分経ったか」をチェックし続ける処理に変更しました。
const targetTime = Date.now() + (15 * 60 * 1000);
const timerId = setInterval(() => {
if (Date.now() > targetTime) {
clearInterval(timerId);
/* なにか */
/* 素敵なことを */
/* 行なう */
}
}, 500);
これなら途中でスリープしていた場合でも開始から15分後に処理が走るし、スリープ中に15分を過ぎていたら、復帰した瞬間に実行されるようになります。
※あまり頻繁だとUIなど他の処理に影響が出るかと思い、500ms間隔での実行にしています。どれくらいの誤差を許容できるかによって設定を変えてください。
おわりに
最初のコードを書いた後、他の人にテストしてもらった結果「時間になっても何も起きないです」と言われたものの、自分の環境では再現しなかった2ので、原因が分かる時間がかかりました……
「気づいてみたら単純なことだった」っていうことは結構ありますよね。