Haydenull

Haydenull

A front-end developer with a passion for using technology to increase personal efficiency and productivity 💡.
twitter

2022年7月3日の週報

JavaScript を使用してカウントダウンとタイマーに注意

1. JS のカウントダウン#

agenda プラグインにはポモドーロ機能を追加する必要があり、usePomodoroを GitHub で見つけました。機能が充実していて、フックを使用するのも便利です。スターの数は多くありませんが、この機能は複雑ではないので、問題があっても自分で対処できると思い、最終的にこれを選びました。

しかし、機能を開発して公開した後、常にタイミングが正確でないことに気付きました。25 分のポモドーロタイマーを設定したのに、1 時間経ってもカウントダウンが終わりませんでした。

後で携帯電話と比較して調べてみると、バックグラウンドでソフトウェアが実行されている場合に誤差が発生することがわかりました。以前にも同様の問題に遭遇したことを思い出しました。ブラウザのタブが非アクティブな状態にあると、タイマーが正確でなくなる可能性があります。

リポジトリを見てみると、問題は次のコードにありました:

// 元のコードでは、setIntervalを使用してカウントダウンの残り時間を計算します
setInterval(tick, 1000)

タブがアクティブでない場合(タブが非表示でブラウザがバックグラウンドにある場合)、setInterval のトリガ間隔は設定された 1000ms ではありません。これは、パフォーマンスとバッテリー消費などの観点からブラウザが設計した仕組みです。

では、どのように処理すればよいでしょうか?

コードが 1 秒ごとに実行されることを JavaScript では保証できないため、外部からアプローチするしかありません。一般的な方法は、システム時刻を参照することです:

function countDown(length) {
  const start = new Date().valueOf()
  const timer = setInterval(() => {
    const now = new Date().valueOf()
    const past = now - start
    if (past <= 0) {
      console.log('count down end')
      clearInterval(timer)
    }
  }, 1000)
}

開始時間とカウントダウンの長さがわかると、終了時間を計算し、コールバックごとに経過時間を知ることができます。タイミングのタスクをシステムに任せ、JavaScript は経過時間をポーリングして調べるだけなので、誤差を回避できます。

これは私が提案したprです。

この方法にも問題があります。ユーザーが常にページを非アクティブな状態にしている場合、カウントダウンが終了するはずの時に setInterval が実行されない可能性があります。ユーザーがタブをアクティブにする必要があります。

この問題を解決する必要がある場合、1 つのアプローチはバックグラウンドでアプリをラップすることです。もう 1 つのアプローチは、状態情報をサーバーに保存し、タイマーが終了したときにサーバーから JavaScript にメッセージを送信することです。

2. js タイマーの注意事項#

基本的な使用方法は非常に簡単ですが、注意が必要ないくつかのポイントについて説明します。

2.1 タイマーのネスト#

setIntervalのコールバックは、別のタイマーの呼び出しをネストすることができます。パフォーマンスへの影響を軽減するため、タイマーのネストが 5 階層を超えると、ブラウザはタイマーの最小間隔を 4ms に強制的に設定します。

2.2 コードの実行時間がタイマーの間隔よりも短いことを確認する#

タイマーコールバックは非同期タスクであり、タイマーを呼び出すメインスレッドの他のコードが完了するまでコールバック関数は実行されません。前のコードの実行時間がタイマーの間隔を超える場合、タイマーは正しいタイミングでトリガされません。したがって、ブラウザはコールバックを正しいタイミングでトリガすることを保証できません。

2.3 非アクティブなタブのタイマーの最小遅延時間 ≥ 1000ms#

バックグラウンドのタブの読み込み負荷(および電力消費)を最適化するため、非アクティブなタブではタイマーの最小遅延時間が 1000ms になります。

2.4 最大遅延値#

ブラウザは 32 ビットの符号付き整数で遅延を保存し、遅延が 2147483647 ミリ秒(約 24.8 日)を超えるとオーバーフローし、この時点でタイマーはすぐに実行されます。

参考記事#

window.setTimeout - Web API リファレンス | MDN

setInterval () - Web API リファレンス | MDN

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。