JavaScriptタイマーの仕組み

JavaScriptタイマーの仕組みを理解することは非常に重要です。 多くの場合、その動作はマルチスレッドの直感的な認識と一致しません。これは、実際には1つのスレッドで実行されるためです。 タイマーを制御できる4つの関数を見てみましょう。

考慮する必要がある主なアイデアは、タイマー遅延期間の精度が保証されないということです。 そもそも、ブラウザはすべての非同期JavaScriptイベント(マウスクリックやタイマーなど)で、このイベントのキューが到着したときにのみ実行します。 これは、次の図に最もよく示されています。







この図から学ぶべき情報はたくさんありますが、これを理解することで、JavaScriptが非同期に実行される方法をより深く理解できます。 この図は時間をミリ秒単位で垂直に表し、青いブロックは実行されたJavaScriptコードのブロックを示しています。 たとえば、最初のブロックは平均18ミリ秒で実行され、マウスクリックは約11ミリ秒で実行をブロックします。



JavaScriptは1つのコードのみを実行できます(実行のシングルスレッドの性質により)。各コードは他の非同期イベントの実行をブロックします。 これは、非同期イベント(マウスクリック、タイマー呼び出し、XMLHttp要求など)が終了すると、キューに追加され、後で実行されることを意味します(もちろん、実装はブラウザーによって異なりますが、「キュー」と呼ぶことに同意しましょう) 。



最初に、2つのタイマーがJavaScriptブロック内で開始することを想像してください。10msの遅延を持つsetTimeoutと同じ遅延を持つsetIntervalです。 タイマーの開始時期によっては、コードの最初のブロックを完了していないときに機能します。 ただし、すぐには機能しないことに注意してください(シングルスレッドのため、これは不可能です)。 代わりに、遅延関数はキューに入れられ、次の利用可能な瞬間に実行されます。



また、最初のJavaScriptブロックの実行中に、マウスクリックが発生します。 この非同期イベント(および予測できないため非同期)のハンドラーは、現時点では直接実行できないため、タイマーのようにキューに入ります。



JavaScriptコードの最初のブロックが実行された後、ブラウザは「実行を待っているものは何ですか?」という質問をします。 この場合、マウスクリックハンドラーとタイマーは保留されます。 ブラウザーはそれらの1つ(クリックハンドラー)を選択して実行します。 タイマーは、実行キューで次に利用可能な時間の部分を待機します。



マウスクリックハンドラーの実行中に、最初のinterval-callbackが起動することに注意してください。 タイマーコールバックと同様に、キューに入れられます。 ただし、間隔が再び機能するとき(タイマーコールバックの実行中)、キューから削除されることに注意してください。 大量のコードが実行されている間にすべてのインターバルコールバックがキューに入った場合、実行終了間の遅延期間なしに呼び出しを待機する一連の関数が形成されます。 代わりに、ブラウザは、キューに別の関数を追加する前に、キューに関数がなくなるまで待機する傾向があります。



したがって、3番目の間隔コールバック操作が既に実行されている瞬間と一致する場合を観察できます。 これは重要な機能を示しています。間隔は現在実行されているものを気にせず、実行間の遅延期間を考慮せずにキューに追加されます。



最後に、2番目のinterval-callbackが完了した後、JavaScriptエンジンが実行する必要のあるものが残っていないことがわかります。 これは、ブラウザーが新しい非同期イベントを再び待機していることを意味します。 これは約50ミリ秒で発生し、インターバルコールバックが再び機能します。 この時点では、ブロックするものは何もないので、すぐに動作します。



setTimeoutとsetIntervalの違いをよく示す例を見てみましょう。

setTimeout(function(){ /* Some long block of code... */ setTimeout(arguments.callee, 10); }, 10); setInterval(function(){ /* Some long block of code... */ }, 10);
      
      





これらの2つのオプションは一見同等ですが、実際はそうではありません。 setTimeoutを使用するコードには、前の呼び出しから少なくとも10ミリ秒の遅延が常にあります(長くすることはできますが、それより小さくすることはできません)。



上記のすべてを要約しましょう。

-JavaScriptエンジンはシングルスレッド環境を使用し、非同期イベントを実行待ちのキューに変換し、

-関数setTimeoutとsetIntervalは、非同期コードで根本的に異なる方法で実行されます。

-現時点でタイマーを実行できない場合、次の実行ポイントまで遅延します(目的の遅延よりも長くなります)。

-間隔(setInterval)は、指定された遅延よりも実行に時間がかかる場合、遅延なく次々に実行できます。



これらはすべて、開発にとって非常に重要な情報です。 JavaScriptエンジンがどのように機能するか、特に多数の非同期イベント(よくあることです)を理解することは、高度なアプリケーションを構築するための優れた基盤となります。



All Articles