ホームページ > 記事 > ウェブフロントエンド > JavaScript の単一スレッドを理解する timer_javascript スキル
1. JavaScript エンジンはシングルスレッドです
以下のコードからわかるように、setTimeout を使用する最初のコードは無限ループであるため、次の 2 つのタイマーは実行されません。
<script type="text/javascript"> setTimeout( function(){ while(true){} } , 100); setTimeout( function(){ alert('你好!setTimeout'); } , 200); setInterval( function(){ alert('你好!setInterval'); } , 200); </script>
ブラウザのカーネルはマルチスレッドであり、カーネルの制御下で相互に連携して、ブラウザには少なくとも 3 つの常駐スレッド (JavaScript エンジン スレッド、GUI レンダリング スレッド、ブラウザ イベント トリガー スレッド) が実装されています。 。
JavaScript エンジンは、イベント駆動型のシングルスレッド実行に基づいています。JS エンジンは、タスク キュー内のタスクの到着を待ってから、それらを処理します。ブラウザには、JS プログラムを実行する JS スレッドが 1 つだけあります。時間。
GUI レンダリング スレッドは、ブラウザ インターフェイスのレンダリングを担当します。このスレッドは、インターフェイスを再描画する必要がある場合 (Repaint)、または特定の操作によってリフローが発生した場合に実行されます。ただし、GUI レンダリング スレッドと JS エンジンは相互に排他的であることに注意してください。JS エンジンが実行されると、GUI スレッドは一時停止され、GUI の更新はキューに保存され、JS エンジンが実行されるとすぐに実行されます。アイドル。
ブラウザーのイベント トリガー スレッド。イベントがトリガーされると、スレッドは保留キューの最後にイベントを追加し、JS エンジンによる処理を待ちます。これらのイベントは、JavaScript エンジンによって現在実行されているコード ブロック (setTimeOut など)、またはブラウザ カーネルの他のスレッド (マウス クリック、AJAX 非同期リクエストなど) から発生する可能性があります。ただし、JS のシングルスレッド関係により、すべてのイベントが発生します。これらのイベントは、JS エンジンによる処理のためにキューに入れられる必要があります。
上の図からわかるように、ブラウザーの JavaScript エンジンはイベント駆動型です。ここでのイベントは、ブラウザーによって割り当てられたさまざまなタスクとみなすことができます。JavaScript エンジンはタスクの到着を待っています。タスク キューでは、シングルスレッドの関係により、これらのタスクはキューに入れられ、エンジンによって次々に処理される必要があります。
t1、t2....tn は異なる時点を表し、tn の下にある対応する小さな四角はその時点のタスクを表します。
t1 時間:
1. GUI レンダリング スレッド
2. ブラウザイベントトリガースレッド:
t1 期間では、ユーザーが最初にマウス ボタンをクリックします。このクリックはブラウザのイベント トリガー スレッドによってキャプチャされ、マウス クリック イベントが形成されます。図からわかるように、このイベントは JavaScript エンジン スレッドに対して非同期に送信されます。タスク キューの最後では、エンジンが t1 でタスクを処理しているため、このマウス クリック イベントは処理を待機しています。
3. タイミングトリガースレッド:
ここでのブラウザ モデルのタイミング カウンタは、JavaScript エンジンによってカウントされません。これは、JavaScript エンジンがブロックされたスレッド状態にある場合、時間の計測とトリガーのタイミングを外部に依存する必要があるためです。したがって、キュー内のタイミング イベントは非同期イベントです。
4. この t1 の期間中に、マウス クリック イベントがトリガーされた後、以前に設定された setTimeout タイミングも到着します。このとき、JavaScript エンジンに対して、タイミング トリガー スレッドが非同期タイミング イベントを生成し、タスク キューに入れます。このイベントは、クリック イベント コールバックの後にキューに入れられ、処理を待機します。同様に、t1 期間内に setInterval タイマーも追加されます。これはインターバル タイマーであるため、これら 2 つのイベントはキューの最後にキューに入れられます。処理される。
5. Ajax 非同期リクエスト:
ブラウザは新しい http スレッド リクエストを開きます。コールバックが事前に設定されている場合、リクエストのステータスが変化すると、非同期スレッドはステータス変更イベントを生成し、JavaScript エンジンの処理キューに入れて処理を待ちます。
2. タスクの実行順序が異なり、表示結果も異なります
1) setTimeout 関数は使用されません
ここでは、インターネット上にあるコード例を使用して説明します。
<a href="#" id="doBtn">do something</a> <div id="status"></div> <script type="text/javascript"> var doBtn = document.getElementById('doBtn') , status = document.getElementById('status'); function sleep(ms) { var start = new Date(); while (new Date() - start <= ms) {} } doBtn.onclick = function(e) { status.innerHTML = 'doing...please wait...'; sleep(3000); // 模拟一个耗时较长的计算过程,3s status.innerHTML = 'done'; return false; }; </script>
上記のコードをFirefoxで実行しました。計画では、「何かをする」ボタンをクリックし、次に「実行中...お待ちください...」を表示し、次にスリープを実行し、最後に「完了」を表示する予定です。
しかし、結果として、クリック後、ブラウザは約 3 秒間停止し、最終的には直接完了と表示されます。
分析によると、status.innerHTML を設定する場合、GUI レンダリング スレッドを実行する必要がありますが、JavaScript エンジン スレッドは引き続き実行され、JavaScript エンジン スレッドと GUI レンダリング スレッドは相互に排他的であることがわかります。したがって、最後に「done」が表示されます。
2) setTimeout 関数を使用します
<a href="#" id="doBtn2">do something timer</a> <div id="status2"></div> <script type="text/javascript"> var doBtn2 = document.getElementById('doBtn2') , status2 = document.getElementById('status2'); function sleep2(ms) { var start = new Date(); while (new Date() - start <= ms) {} } doBtn2.onclick = function(e) { status2.innerHTML = 'doing...please wait...'; setTimeout(function() { sleep2(3000); status2.innerHTML = 'done'; }, 100); return false; }; </script>
「doing...please wait...」の後に setTimeout を追加して実行を遅らせ、ブラウザにレンダリング時間を与えます。このとき、「doing...please wait...」という文字が表示されます。次にスリープ機能を実行し、最後に「done」を表示します。
一部のネットユーザーは、この問題が Firefox では機能しないことに気づきました。その後、私はコードを修正し、ページ構造がロードされた後にローカル変数の宣言と onclick のバインディングを追加しました。 、 、スクリプト操作を再度実行します。
<script type="text/javascript"> function sleep(ms) { //... } window.onload = function() { var doBtn = document.getElementById('doBtn'), status = document.getElementById('status'); var doBtn2 = document.getElementById('doBtn2') , status2 = document.getElementById('status2'); doBtn.onclick = function(e) { //... }; doBtn2.onclick = function(e) { //... }; }; </script>
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。