JavaScript タイマーの仕組み

高洛峰
高洛峰オリジナル
2016-11-25 09:15:142326ブラウズ

以下の内容を読む前に、コードの小さな部分を読んでください。コードの目的が理解できる場合は、理解できるので、さらに読む必要はありません。

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

タイマーは非常に素晴らしいものですが、多くの人はその構文しか知らず、その原理を理解していません。タイマーは、一定の時間 (ミリ秒) を設定することでコードを非同期に実行します。 Javascript はシングルスレッド言語であるため、タイマーはこの言語の制限を回避してコードを実行する機能を提供します。

今日はタイマーの仕組みを簡単に説明します。

JavaScript はタイマーを構築および操作するための 3 つの関数を提供します

1 var id = setTimeout(fn, late);

2 var id = setInterval(fn, late);

3 clearInterval(id);

特定の構文については詳しく説明しません。マニュアルを確認してください。タイマーの仕組みを理解するには、時間の遅延は保証されないという 1 つの概念を念頭に置く必要があります。これはどういう意味ですか? このように setTimeout(fn, 500) を記述したからといって、fn が 500 ミリ秒後に必ず実行されるわけではありません。遅延が長くなる可能性があります。 JavaScript はシングルスレッド言語であるため、すべての非同期イベント (タイマー、マウス イベント、XMLHttpRequest の完了など) は、プログラムの実行中にギャップがある場合にのみ実行されます。ユーザーは全能ではなく、何を書くかは最終的にはブラウザーに依存することを理解する必要があります。

下の写真は問題を非常によく示しています。偉大な John Resig に感謝します。

JavaScript タイマーの仕組み

上から下に見ると、左側の数字は時間 (ミリ秒) を表し、右側のテキストは一連の非同期イベントの設定とトリガーを表し、中央のコード ブロックを表します。一番上の JavaScript コード ブロックは、ブラウザの読み込み時に実行されるフラグメントである可能性があり、これには約 18 ミリ秒かかります。すぐ下のマウス クリック コールバック コード ブロックは、マウス イベントがトリガーされたときのコールバック関数である可能性があります。これには約 18 ミリ秒かかります。 、 等々。

JavaScript のシングルスレッドの性質により、一度に実行できるブロックは 1 つだけであるため、コードの最初のブロックが実行されるとき (合計 18 ミリ秒間実行されました)、2 つのタイマーが構築され、その間にユーザーはマウスをクリックした可能性があります (Web ページを開いた直後、読み込みが完了する前に表示が崩れてしまったことがありますか?)ユーザーがマウスをクリックした直後にコールバック関数を実行する必要があるのは当然ですが、JavaScript の実行レーンは 1 つしかなく、18 ミリ秒が完了する前に他のコード ブロックをキューに入れることができるのは必要な場合のみです。追いつく余地はありません。図からわかるように、両方のタイマーには 10 ミリ秒の遅延があります。18 ミリ秒の実行が終了する前に setTimeout もトリガーされます。これをキューに入れる方法はありません。

ついに、18ミリ秒後、空からの神々しい雷鳴が前を走っていた車を真っ二つに裂き、後ろに並んでいた2人は追い抜くことができましたが、1人ずつ行かなければならず、並んで走ることはできませんでした。それで、誰が最初に通過するでしょうか?そこで殴り合っている二人がいますか?いいえ、最終決定権はブラウザーにあります。ブラウザーは、マウス クリック イベントが最初に通過し、setTimeout が待機し続けることができるのは 11 ミリ秒だけであると言います。図に注目してください。マウス イベント コールバック関数が実行されると、別のタイマー イベント (setInterval) がトリガーされて待機しており、setTimeout の後ろに位置する必要があります。

11 ミリ秒が経過し、setTimeout が 2 回目にトリガーされることに注意してください。この時点でまだ通常どおりキューに入れられている場合、最終的にはどうなりますか?その後、2 つの setInterval が連続して実行され、設定した遅延は役に立ちません。したがって、ブラウザは非常に賢く、setInterval を処理するときに、キューに登録されているものがすでに存在することが判明すると、新しいものを直接強制終了します。

次に、キューに入れられた setInterval が初めてトリガーされ、実行が開始されます。今度は 3 番目のトリガーが再び来ます。そのため、ブラウザーはそれを強制終了せずに返します。したがって、これら 2 つの setInterval の実行間に間隔がないことがわかります。スライドショーを作成している場合は、この状況が発生したときにコードに問題があるかどうかを慎重に検討する必要があります。

最後に、他の要因が setInterval に干渉しない場合 (ユーザーが MM によって呼び出された場合)、setInterval は必要な手順に従って実行されます。

この時点で、冒頭のコードは理解できます。

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

これら 2 つの関数は同じ効果があるように見えますが、そうではありません。最初のコード ブロックは常に 10 ミリ秒の遅延で実行されますが、ほとんどの場合、10 ミリ秒を超えます。 2 番目のトリガーは、前のトリガーが実行されたかどうかに関係なく、10 ミリ秒ごとに実行を試みます。

要約すると、4 つのポイントです

• JavaScript エンジンにはスレッドが 1 つしかないため、特定の非同期イベントが強制的にキューに入れられます

• 非同期コードを実行する場合、setTimeout と setInterval には大きな違いがあります

• タイマーが実行がブロックされている場合、コード実行ギャップが発生するまで待機します。通常、その時間は予想よりも長くなります

• コールバック関数の実行時間が間隔よりも長い場合、間隔が次々に実行される可能性があります


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。