この記事の内容は、JS の動作メカニズム (同期、非同期、イベント ループ) に関するものです。必要な方は参考にしていただければ幸いです。 。
1. JS はなぜシングルスレッドなのでしょうか?
Javascript 言語の主な特徴は、それがシングルスレッドであり、同時に同じことしか実行できないことです。 JSはマルチスレッド化できないのでしょうか?
ブラウザスクリプト言語としての Javascript の主な目的は、ユーザーと対話し、DOM を操作することです。これにより、Javascript はシングルスレッドでのみ実行可能であると判断されます。そうしないと、非常に複雑な同期の問題が発生します。例: Javascript に同時に 2 つのスレッドがあるとします。1 つのスレッドが特定の DOM ノードにコンテンツを追加し、もう 1 つのスレッドがノードを削除するとします。この場合、ブラウザはどちらを使用する必要がありますか。
そのため、複雑さを避けるために、JavaScript は誕生以来シングルスレッドであり、これがこの言語の中心的な機能となっており、今後も変更されることはありません。
マルチコア CPU の計算能力を活用するために、HTML5 は Web Wker 標準を提案しています。これにより、JavaScript スクリプトは複数のスレッドを作成できますが、子スレッドはメインスレッドによって完全に制御され、スレッドを操作することはできません。ドム。したがって、この新しい標準は JavaScript のシングルスレッドの性質を変更しません。
2. 同期と非同期
関数 A があるとします:
A (args...) {...}
同期: 関数 A を呼び出すとき、呼び出し元は If期待される結果がすぐに得られる場合、関数は同期的です。
非同期: 関数 A を呼び出すときに、呼び出し元が期待した結果をすぐには取得できないが、将来的に特定の手段 (時間のかかる、遅延、イベントトリガー) を通じて取得する必要がある場合、この関数は非同期です。
3. JS が非同期操作を実装する方法
JS はシングルスレッドですが、ブラウザーのカーネルは、いくつかの時間のかかるタスクやさまざまな非同期操作のために追加のスレッドを開きます。たとえば、onlcik、setTimeout、および ajax は、ブラウザ カーネルの DOM によって異なる方法で処理されます。 Bingding、ネットワーク、タイマー モジュールが実行され、実行されたタスクが実行結果を取得すると、対応するコールバック関数がタスク キューに配置されます。したがって、JS は常にシングルスレッドであり、非同期操作を実装するのはブラウザです。
上の図では、DOM リクエスト、Ajax リクエスト、setTimeout およびその他の WebAPI がコール スタックで検出されると、それらは処理のためにブラウザ カーネルの他のモジュールに渡されます。WebKit カーネルには重要な機能があります。 module は webcoew モジュールです。図の WebAPI で示されている 3 つの API について、Webcore は、基礎となる実装を処理するために、それぞれ DOM バインディング、ネットワーク、およびタイマー モジュールを提供します。これらのモジュールがこれらの操作の処理を完了したら、コールバック関数をタスク キューに入れ、スタック内のタスクが実行されるのを待ってから、タスク キュー内のコールバック関数を実行します。
概要:
1. すべてのコードは、関数呼び出しスタック内の呼び出しを通じて実行する必要があります
2. 前の記事で説明した API が発生すると、そのコードは の他の部分に渡されます。ブラウザカーネル処理用モジュール
3. コールバック関数はタスクキューに格納されます
4. コールスタック内のタスクが実行されるまで待機し、その後タスクキュー内のタスクを実行します
動作メカニズム
(1 ) すべての同期タスクはメインスレッドで実行され、実行スタックを形成します。
(2) メインスレッドの他に「タスクキュー」もあります。非同期タスクは演算結果がある限り「タスクキュー」にイベント(コールバック関数)が置かれます。
(3) 「実行スタック」内のすべての同期タスクが完了すると、システムは「タスクキュー」を読み取り、その中にどのようなイベントがあるかを確認します。対応する非同期タスクは待機状態を終了します。実行スタックに入り、実行を開始します。
(4) メインスレッドは上記の 3 番目のステップを繰り返し続けます
タスクキュー
タスクキューについては上でも触れましたが、タスクキューとは一体何なのでしょうか?たとえば
ES6標準では、タスクキューはマクロタスクとマイクロタスクに分かれています
1.マクロタスクには、スクリプト(コード全体)、setTimeout、setInterval、setImmediate、I/O、UIレンダリングが含まれます
2.micro-task には、process.nextTick、Promises、Object.observe、MutationObserver が含まれます
イベントループのシーケンスは、スクリプトから最初のループを開始し、その後、マクロタスクが発生すると、それを処理するモジュールに渡されます。コールバック関数はマクロタスクのキューに入れられます。その中で、マイクロタスクに遭遇すると、そのコールバック関数もマイクロタスクのキューに入れられます。関数呼び出しスタックがクリアされ、グローバル実行コンテキストのみが残るまで、すべてのマイクロタスクが実行され始めます。すべての実行可能なマイクロタスクが実行された後。ループはマクロタスク内のタスクキューを再度実行し、実行後にすべてのマイクロタスクを実行し、このようにループが続きます。
次に、実行プロセスを分析しましょう:
(function test() { setTimeout(function() {console.log(4)}, 0); new Promise(function executor(resolve) { console.log(1); for( var i=0 ; i<10000 ; i++ ) { i == 9999 && resolve(); } console.log(2); }).then(function() { console.log(5); }); console.log(3); })()
1. グローバル コンテキストをスタックにプッシュし、その中のコードの実行を開始します。
2. setTimeout を実行し、マクロタスクとしてタイマー モジュールに渡し、そのコールバック関数を独自のキューに入れます。
3. Promise インスタンスを実行し、Promise をスタックにプッシュします。最初のパラメーターは、現在のタスクで出力 1 を直接実行します。
4. ループ本体を実行し、resolve 関数に遭遇し、それをスタックにプッシュして実行後にポップアウトし、Promise ステータスを Fulfilled に変更し、then メソッドに遭遇したら、Promise を出力します。マイクロタスクとしてのタスクキュー。
6. コードの実行を続けて 3 を出力します。
7. 3 を出力した後、最初のマクロタスク コードが実行され、キュー内のすべてのマイクロタスクの実行が開始されます。 then のコールバック関数はスタックにプッシュされてからポップアウトされ、5 を出力します。
8. この時点で、すべての micao タスクが実行され、最初のサイクルが終了します。 2回目のループはsetTimeoutのタスクキューから始まり、setTimeoutのコールバック関数がスタックにプッシュされてからポップアウトされます。このとき、4が出力されます。
概要: 1. 異なるタスクは異なるタスクキューに入れられます。2. 最初にマクロタスクを実行し、関数呼び出しスタックがクリアされるまで待ってから、キュー内のすべてのマイクロタスクを実行します。
3. すべてのマイクロタスクが実行されるまで待ってから、マクロタスク内のタスクキューから実行を開始すると、このようにループが続きます。
4. マクロタスク(マイクロタスク)のキューが複数ある場合、イベントループの順序は上記のマクロタスク(マイクロタスク)の分類に書かれた順序で実行されます。
概要:
JS エンジンは、JS コードを解析するときに、呼び出しスタック内のタスクを処理するときに、メイン スレッド (メイン スレッド) と呼び出しスタック (呼び出しスタック) を作成します。待たなければなりません。いくつかの非同期操作が実行されると、それらは処理のためにブラウザーカーネルの他のモジュールに渡されます(WebKitを例に取ると、それはWebコアモジュールです)。処理が完了した後、タスク(コールバック関数)が実行されます。 ) はタスクキューに配置されます。
通常、異なる非同期タスクのコールバック関数は異なるタスクキューに配置され、コールスタック内のすべてのタスクが実行された後、タスクキュー内のタスク(コールバック関数)が実行されます。
おすすめ関連記事:
JavaScriptでのこのキーワードの使用法(コード付き)
以上がJSの動作機構:同期・非同期・イベントループ(Event Loop)の解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。