JavaScript は Web のバックボーンであり、数十億の Web サイトやアプリケーションの動的なクライアント側機能を強化します。しかし、JavaScript がバックグラウンドでどのように魔法を働いているのか疑問に思ったことはありますか?この投稿では、JavaScript のシングルスレッドの性質の内部動作を詳しく調べ、非同期プログラミングの概念を探っていきます。
JavaScript が「シングルスレッド」であると言うとき、それは単一の呼び出しスタックがあることを意味します。コールスタックは本質的に、JavaScript が実行中の関数を追跡する構造です。これは後入れ先出し (LIFO) 順序に従います。つまり、スタックにプッシュされた最後の関数が最初に終了します。これがどのように機能するかの例を次に示します:
function first() { console.log('First function'); } function second() { console.log('Second function'); } first(); second();
この例では、first() 関数がスタックに追加されて実行されます。完了するとポップオフされ、 Second() 関数がスタックにプッシュされて次に実行されます。
シングルスレッド言語は一度に 1 つのことしか実行できないため制限があるように見えるかもしれませんが、JavaScript は非同期メカニズムを巧みに使用することでマルチタスクをシミュレートできます。
JavaScript は非同期実行を使用して、ネットワーク要求、ファイル I/O、タイマーなど、完了までに長時間かかる可能性のある操作を処理します。シングルスレッドであるにもかかわらず、イベント ループとコールバック キューのおかげで複数のタスクを同時に管理できます。
イベント ループは、JavaScript の同時実行モデルの中核となる概念です。その主な役割は、JavaScript が非同期コードの実行を処理する方法を管理することです。仕組みは次のとおりです:
同期コードが最初に実行されます。 JavaScript が開始されると、コール スタックを使用して、グローバル スコープ内のすべてのコードが 1 行ずつ同期的に実行されます。
非同期タスクは、Web API (setTimeout、fetch など) または Node.js API に送信され、バックグラウンドで処理されます。
コールバック キューは、非同期操作が完了した後に配置される場所です。
イベント ループは、呼び出しスタックが空かどうかを継続的にチェックします。スタックが空の場合、コールバック キューから最初の項目を取得してコール スタックにプッシュし、実行できるようにします。
非同期 JavaScript の魅力は、イベント ループ、コール スタック、コールバック キューの間の相互作用にあります。非同期操作はコール スタックをブロックしません。つまり、JavaScript はバックグラウンド タスクが完了するのを待っている間も他のコードの実行を続けることができます。
setTimeout 関数を使用した次の例を考えてみましょう:
console.log('Start'); setTimeout(() => { console.log('This runs after 2 seconds'); }, 2000); console.log('End');
これが段階的に起こることです:
JavaScript は「開始」を出力します。
setTimeout 関数が呼び出されますが、実行を 2 秒間ブロックする代わりに Web API に送信され、バックグラウンドで実行されます。
JavaScript は「End」を出力し、setTimeout の完了を待たずに実行を続行します。
2 秒後、setTimeout 内のコールバック関数がコールバック キューに配置されます。
イベント ループは、コール スタックが空かどうかを確認し (実際に空です)、コールバック関数をスタックにプッシュして実行し、「これは 2 秒後に実行されます」と出力します。
最新の JavaScript で非同期タスクを処理するもう 1 つの一般的な方法は、Promises と async/await 構文を使用することです。これは、深くネストされたコールバック (「コールバック 地獄」とも呼ばれる) を回避してコードを読みやすくします。
Promise は、非同期操作の最終的な完了 (または失敗) とその結果の値を表します。以下に例を示します:
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise resolved!'); }, 1000); }); promise.then(result => { console.log(result); // Output after 1 second: 'Promise resolved!' });
コールバックに依存する代わりに、then() を使用して、Promise が解決されたときに何が起こるかを処理できます。より同期的に見える方法で非同期コードを処理したい場合は、 async/await:
を使用できます。
async function asyncExample() { const result = await promise; console.log(result); // Output after 1 second: 'Promise resolved!' } asyncExample();
これにより、JavaScript が内部でノンブロッキングのままであっても、コードの次の行に進む前に非同期タスクが完了するのを「待つ」ことができるようになり、コードがすっきりして理解しやすくなります。
呼び出しスタック: 同期コードが実行される場所。
Web API/Node.js API: 非同期タスク (ネットワーク リクエストなど) が処理される外部環境。
コールバック キュー: 非同期タスクの結果が実行のためにコール スタックにプッシュされるのを待つキュー。
イベント ループ: コール スタックとコールバック キューの間で調整を行い、タスクが正しい順序で処理されるようにするシステム。
JavaScript のシングルスレッドの性質は一見すると制限があるように思えるかもしれませんが、その非同期機能により複数のタスクを効率的に管理できます。イベント ループ、コールバック キュー、Promise などのメカニズムを通じて、JavaScript は直感的で同期的に見えるコーディング スタイルを維持しながら、複雑なノンブロッキング操作を処理できます。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3