JavaScriptの動作仕組みイベントループ(Event Loop)の詳しい解説_javascriptスキル
1. JavaScript はなぜシングルスレッドなのでしょうか?
JavaScript 言語の主な機能はシングルスレッドです。これは、一度に 1 つのことしか実行できないことを意味します。では、なぜ JavaScript は複数のスレッドを持てないのでしょうか?これにより効率が向上します。
JavaScript の単一スレッドはその目的に関連しています。ブラウザーのスクリプト言語としての JavaScript の主な目的は、ユーザーと対話し、DOM を操作することです。これにより、シングルスレッドのみが可能であることが決まります。そうでない場合は、非常に複雑な同期の問題が発生します。たとえば、JavaScript に同時に 2 つのスレッドがあるとします。1 つのスレッドが特定の DOM ノードにコンテンツを追加し、もう 1 つのスレッドがそのノードを削除するとします。この場合、ブラウザーはどちらのスレッドを使用すればよいでしょうか。
したがって、複雑さを避けるために、JavaScript は誕生以来シングルスレッドであり、これは言語の中核的な機能となっており、今後も変更されることはありません。
マルチコア CPU の計算能力を活用するために、HTML5 は Web Worker 標準を提案しています。これにより、JavaScript スクリプトは複数のスレッドを作成できますが、子スレッドはメインスレッドによって完全に制御され、子スレッドを操作してはなりません。ドム。したがって、この新しい標準は JavaScript のシングルスレッドの性質を変更しません。
2. タスクキュー
シングルスレッドとは、すべてのタスクをキューに入れる必要があり、前のタスクが完了するまで次のタスクは実行されないことを意味します。前のタスクに時間がかかると、次のタスクも待たされることになります。
キューが大量の計算によるもので、CPU がビジー状態である場合は、それを忘れてください。しかし、多くの場合、IO デバイス (入出力デバイス) が非常に遅いため、CPU はアイドル状態になります (Ajax 操作など)。ネットワークからデータを読み取る)、続行する前に結果が出るまで待つ必要があります。
JavaScript 言語の設計者は、現時点では、CPU が IO デバイスを完全に無視し、待機中のタスクを一時停止し、後のタスクを最初に実行できることに気づきました。 IO デバイスが結果を返すまで待ってから、戻って中断されたタスクの実行を続行します。
その結果、JavaScript には 2 つの実行方法があります。1 つは CPU が順番に実行し、前のタスクが終了してから次のタスクが実行される方法 (同期実行と呼ばれます)、もう 1 つは CPU がタスクをスキップする方法です。待ち時間が長い場合は、後続のタスクを最初に処理します。これを非同期実行と呼びます。どの実行方法を使用するかを選択するのはプログラマの責任です。
非同期実行の具体的な動作仕組みは以下の通りです。 (同期実行についても、非同期タスクなしの非同期実行と見なすことができるため、同じことが当てはまります。)
(1) すべてのタスクはメインスレッドで実行され、実行コンテキストスタックを形成します。
(2) メインスレッドの他に「タスクキュー」があります。システムは非同期タスクを「タスクキュー」に入れ、後続のタスクを実行し続けます。
(3) 「実行スタック」内のすべてのタスクが実行されると、システムは「タスクキュー」を読み取ります。このとき、非同期タスクが待ち状態を終了していれば、「タスクキュー」から実行スタックに入り、実行を再開します。
(4) メインスレッドは上記の 3 番目のステップを繰り返し続けます。
下の図はメインスレッドとタスクキューの模式図です。
メインスレッドが空である限り、「タスクキュー」を読み取ります。これが JavaScript の実行メカニズムです。このプロセスは繰り返され続けます。
3. イベントとコールバック関数
「タスク キュー」は本質的にイベント キュー (メッセージ キューとしても理解できます) であり、IO デバイスがタスクを完了すると、関連する非同期タスクが入ることができることを示すイベントが「タスク キュー」に追加されます。実行スタック」。メインスレッドは「タスクキュー」を読み取ります。これは、その中のイベントを読み取ることを意味します。
「タスク キュー」内のイベントには、IO デバイス イベントに加えて、ユーザーが生成したイベント (マウス クリック、ページ スクロールなど) も含まれます。コールバック関数が指定されている限り、これらのイベントは発生時に「タスクキュー」に入り、メインスレッドによる読み取りを待ちます。
いわゆる「コールバック関数」は、メインスレッドによってハングアップされるコードです。非同期タスクはコールバック関数を指定する必要があります。非同期タスクが「タスク キュー」から実行スタックに戻ると、コールバック関数が実行されます。
「タスクキュー」は先入れ先出しのデータ構造で、最初にランク付けされたイベントが最初にメインスレッドに返されます。メインスレッドの読み取りプロセスは基本的に自動であり、実行スタックがクリアされるとすぐに、「タスクキュー」の最初のイベントが自動的にメインスレッドに戻ります。ただし、後述する「タイマー」機能により、メインスレッドは実行時間をチェックする必要があり、特定のイベントは指定された時間にメインスレッドに返さなければなりません。
4. イベントループ
メインスレッドは「タスクキュー」からイベントを読み取ります。このプロセスは周期的であるため、動作メカニズム全体はイベントループとも呼ばれます。
イベント ループをよりよく理解するために、下の図をご覧ください (フィリップ ロバーツのスピーチ「助けて、イベント ループにはまってしまいました」から引用)。
上の図では、メインスレッドの実行中にヒープとスタックが生成され、スタック内のコードはさまざまな外部 API を呼び出して「タスク キュー」にさまざまなイベント (クリック、ロードなど) を追加します。 "。 終わり)。スタック内のコードが実行されている限り、メインスレッドは「タスクキュー」を読み取り、それらのイベントに対応するコールバック関数を順番に実行します。
実行スタック内のコードは、常に「タスクキュー」を読み取る前に実行されます。以下の例を見てください。
var req = 新しい XMLHttpRequest();
req.open('GET', URL); req.onload = 関数 (){}; req.onerror = 関数 (){}; req.send();
上記のコードの req.send メソッドは、サーバーにデータを送信する Ajax 操作です。これは非同期タスクです。つまり、現在のスクリプトのすべてのコードが実行されるまで、システムは「タスク キュー」を読み取りません。したがって、以下の記述に相当します。
req.onload = 関数 (){}; req.onerror = 関数 (){};
つまり、コールバック関数 (onload と onerror) を指定する部分が send() メソッドの前か後かは関係ありません。これらは実行スタックの一部であり、システムは常にコールバック関数を読み取る前に実行するためです。 「タスクキュー」」。
5. タイマー
「タスクキュー」には、非同期タスクを配置するだけでなく、時間指定イベントを配置する機能もあります。つまり、特定のコードがどのくらいの時間後に実行されるかを指定できます。これは「タイマー」関数と呼ばれ、定期的に実行されるコードです。
タイマー関数は、主に setTimeout() と setInterval() の 2 つの関数によって実行されます。それらの内部動作メカニズムはまったく同じです。違いは、前者で指定されたコードが 1 回実行されるのに対し、後者は繰り返し実行されることです。 。以下では主に setTimeout() について説明します。
setTimeout() は 2 つのパラメータを受け入れます。1 つ目はコールバック関数で、2 つ目は実行を遅らせるミリ秒数です。コードをコピーします
setTimeout() が 2 行目の実行を 1000 ミリ秒後まで遅らせるため、上記のコードの実行結果は 1、3、2 になります。
setTimeout() の 2 番目のパラメーターが 0 に設定されている場合、現在のコードが実行された (実行スタックがクリアされた) 後、指定されたコールバック関数がすぐに (0 ミリ秒間隔) 実行されることを意味します。
上記のコードの実行結果は常に 2, 1 になります。これは、2 行目の実行後にのみシステムが「タスク キュー」内のコールバック関数を実行するためです。
HTML5 標準では、setTimeout() の第 2 パラメータの最小値 (最短間隔) を 4 ミリ秒以上にすることが規定されており、この値より小さい場合は自動的に増加します。これより前の古いブラウザでは、最小間隔が 10 ミリ秒に設定されていました。
さらに、これらの DOM 変更 (特にページの再レンダリングを伴う変更) は通常、すぐには実行されず、16 ミリ秒ごとに実行されます。この時点では、setTimeout() よりも requestAnimationFrame() を使用した方が効果が高くなります。
setTimeout() はイベントを「タスク キュー」に挿入するだけであることに注意してください。メイン スレッドは、指定されたコールバック関数を実行する前に、現在のコード (実行スタック) の実行が終了するまで待機する必要があります。現在のコードに時間がかかる場合は、長時間かかる可能性があるため、setTimeout() で指定された時間にコールバック関数が実行されることを保証する方法はありません。
6. Node.jsのイベントループ
Node.js もシングルスレッドのイベント ループですが、その動作メカニズムはブラウザ環境とは異なります。
下の図をご覧ください (@BusyRich による)。
上の図によると、Node.js の動作メカニズムは次のとおりです。
(1) V8 エンジンは JavaScript スクリプトを解析します。
(2) 解析されたコードはノード API を呼び出します。
(3) libuv ライブラリは、ノード API の実行を担当します。異なるタスクを異なるスレッドに割り当ててイベントループ(イベントループ)を形成し、タスクの実行結果を非同期でV8エンジンに返します。
(4) V8 エンジンは結果をユーザーに返します。
2 つのメソッド setTimeout と setInterval に加えて、Node.js は「タスク キュー」に関連する他の 2 つのメソッド、process.nextTick と setImmediate も提供します。これらは、「タスクキュー」についての理解を深めるのに役立ちます。
process.nextTick メソッドは、メインスレッドが次回「タスクキュー」を読み取る前に、現在の「実行スタック」の最後でコールバック関数をトリガーできます。つまり、指定したタスクは常にすべての非同期タスクの前に発生します。 setImmediate メソッドは、現在の「タスク キュー」の最後でコールバック関数をトリガーします。つまり、指定されたタスクは、次回メイン スレッドが「タスク キュー」を読み取るときに常に実行されます。これは setTimeout( とよく似ています) fn、0) 。以下の例を参照してください (StackOverflow 経由)。
process.nextTick(function A() {
console.log(1);
process.nextTick(function B(){console.log(2);});
});
setTimeout(関数タイムアウト() {
console.log('タイムアウトが発生しました');
}, 0)
// 1
// 2
// タイムアウトが発生しました
上記のコードでは、process.nextTick メソッドで指定されたコールバック関数は常に現在の「実行スタック」の最後でトリガーされるため、setTimeout で指定されたコールバック関数のタイムアウト前に関数 A が実行されるだけでなく、関数 B も実行されます。タイムアウト前に実行されます。これは、複数の process.nextTick ステートメントがある場合 (ネストされているかどうかに関係なく)、それらはすべて現在の「実行スタック」で実行されることを意味します。
次に、setImmediate を見てください。
setImmediate(function A() {
console.log(1);
setImmediate(function B(){console.log(2);});
});
setTimeout(関数タイムアウト() {
console.log('タイムアウトが発生しました');
}, 0)
// 1
// タイムアウトが発生しました
// 2
上記のコードには、2 つの setImmediate があります。最初の setImmediate は、コールバック関数 A が現在の「タスク キュー」(次の「イベント ループ」) の終了時にトリガーされることを指定します。次に、setTimeout は、コールバック関数のタイムアウトが現在の「タスク」の終了時にトリガーされることも指定します。 queue" であるため、出力結果では TIMEOUT FIRED が 1 よりも下にランクされます。 TIMEOUT FIRED に次ぐ 2 位については、setImmediate のもう 1 つの重要な機能によるものです。「イベント ループ」は、setImmediate で指定された 1 つのコールバック関数のみをトリガーできます。
ここから重要な違いがわかります。複数の process.nextTick ステートメントは常に一度に実行されますが、複数の setImmediate ステートメントは複数回実行する必要があります。実際、これが Node.js バージョン 10.0 で setImmediate メソッドを追加した理由です。そうしないと、次のような process.nextTick への再帰呼び出しが無限に行われ、メイン スレッドが「イベント キュー」をまったく読み取れなくなります。
process.nextTick(function foo() {
process.nextTick(foo);
});
実際、ここで再帰的 process.nextTick を記述すると、Node.js は警告をスローし、それを setImmediate に変更するように求めます。
また、 process.nextTick で指定されたコールバック関数はこの「イベントループ」でトリガーされ、setImmediate で指定されたコールバック関数は次の「イベントループ」でトリガーされるため、前者の方が常に後者より先に発生することは明らかです。 、実行効率も高いです(「タスクキュー」を確認する必要がないため)。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。
