
VUE3.0 をすぐに始める方法:
JavaScript はシングルスレッドですが、イベント ループは可能な限りシステム カーネルを使用して、Node.js がノンブロッキング I/O 操作を実行できるようにします。最新のカーネルはマルチスレッドですが、マルチスレッド タスクを処理できます。背景。タスクが完了すると、カーネルは Node.js に通知し、実行用のループに適切なコールバックが追加されます。
Node.js が実行を開始すると、イベント ループが
発生します。まず初期化され、提供された入力スクリプトを処理します (または REPL に入力しますが、これについてはこのドキュメントでは説明しません)。これにより、非同期 API 呼び出しが実行され、タイマーがスケジュールされ、または process.nextTick() が呼び出されます。イベントループの処理を開始します。
以下の図は、
イベントループの実行シーケンスの概略を示しています。
┌─>│ タイマー │ │ └─────────┬─────────┘ │ ┌─────────┴─────────┐ │ │ 保留中のコールバック │ │ └─────────┬─────────┘ │ ┌─────────┴─────────┐ │ │ アイドル、準備 │ │ ━─────────┬───────┘ ┌───────┐ │ ┌─────────┴───────┐ │ 受信: │ │ │ ポーリング │<─────┤ 接続、 │ │ └─────────┬─────────┘ │ データ等 │ │ ┌─────────┴───────┐ ━━━━━━┘ │ │ 確認する │ │ └─────────┬─────────┘ │ ┌─────────┴─────────┐ └─┤ コールバックを閉じる │ ━━━━━━━━━━┘各
ボックスはイベントループのステージを表します。
ただし、各ステージには FIFO キューのコールバック実行があります。 、各ステージは独自の方法で実行されます。一般的に、イベント ループはステージに入ると、現在のステージであらゆる操作を実行し、キューが完全に消費されるか実行されるまで、現在のステージのキューでコールバックの実行を開始します。最大のデータ。キューが使い果たされるか、最大サイズに達すると、イベント ループは次のフェーズに移動します。
イベント ループの各プロセスで、 Node .js は、非同期 I/O とタイマーを待機しているかどうかを確認し、待機していない場合は
タイマーは、必要な時間ではなく、コールバックが実行される重要なポイントを指定します。タイマーは指定された時間が経過するとできるだけ早く実行されますが、オペレーティング システムのスケジュールやその他のコールバックにより実行が遅れる場合があります。
技術的に言えば、ポーリング フェーズによってコールバックがいつ実行されるかが決まります。
たとえば、100 ミリ秒後に実行されるようにタイマーを設定しましたが、スクリプトはファイルを非同期で読み取り、
const fs = require('fs') ;かかります。
関数 someAsyncOperation(callback) {
// 完了までに 95 ミリ秒かかると仮定します
fs.readFile('/path/to/file', callback);
}
const timeoutScheduled = Date.now();
setTimeout(() => {
const late = Date.now() - timeoutScheduled;
console.log(`スケジュールされてから ${lay}ms が経過しました`);
}, 100);
// 完了までに 95 ミリ秒かかる someAsyncOperation を実行します
someAsyncOperation(() => {
const startCallback = Date.now();
// 10ms かかる処理を実行します...
while (Date.now() - startCallback < 10) {
// 何もしない
}
イベント ループがポーリング フェーズに入ると、空のキューが存在するため (fs.readFile() がまだ完了していない)、95 ミリ秒後に最速のタイマーしきい値に達するまで残りのミリ秒間待機します
。
.readfile()はファイルの読み取りを完了し、10ミリ秒かかり、コールバックが完了したときに、実行するキューにコールバックがあり、イベントループがタイマーフェーズに戻ります。タイマーのコールバックを実行します。 In this example, you will see that the timer is delayed for 105 ms before executing.
To prevent the poll phase from blocking the event loop, libuv (the C language library that implements the event loop and all asynchronous behavior on the platform) also hasポーリング フェーズ 最大停止ポーリングをさらに多くのイベント
このフェーズは、特定のシステム操作 (TCP エラー タイプなど) のコールバックを実行します。 たとえば、一部の *nix システムは、接続しようとしたときに TCP ソケットが ECONNREFUSED を受信した場合、エラーが報告されるのを待ちます。 これは、保留中のコールバック フェーズ中に実行するためにキューに入れられます。
フェーズ
には、イベントのキューが発生しない場合
ポーリングキューが空になる
とすぐに実行されますタイマーが期限切れになったかどうかを検出し、期限切れになった場合、イベント ループはタイマー ステージに到達し、ポーリング フェーズの完了後すぐにタイマー コールバック チェックを実行できる
になります。 如果轮询阶段变得空闲并且脚本已使用setImmediate() 排队,则事件循环可能会继续到check 阶段而不是等待。
setImmediate() は実際には、イベント ループの別のフェーズで実行される特別なタイマーです。 libuv API を使用して、ポーリング フェーズの完了後に実行されるコールバックをスケジュールします。
通常、コードが実行されると、イベントループは最終的に投票フェーズに到達し、着信接続、リクエストなどを待ちます。ただし、setImmediate() を使用してコールバックがスケジュールされ、ポーリング フェーズがアイドル状態になると、コールバックは終了し、ポーリング イベントを待たずにチェック フェーズに進みます。
ソケットまたは操作が
突然閉じられた場合(socket.destroy、この段階に閉じるイベントが送信されます。
setTimeout() と setTimeout() は似ていますが、いつ呼び出されるかによって動作が異なります。
各コールバックが実行される順序は、次によって決まります。この環境で呼び出される順序は、同じモジュールが同時に呼び出された場合、プロセスのパフォーマンスによって制限されます(これは、このマシンで実行されている他のアプリケーションによっても影響を受けます
) 、I/Oで次のスクリプトを実行しない場合、プロセスのパフォーマンスの影響を受けますが、これら2つのタイマーの実行順序を決定することはできません:
// Timeout_vs_immediate.js
setTimeout(() => {
console.log('タイムアウト');
}, 0);
setImmediate(() => {
console.log('即時');
}); $ ノードタイムアウト_vs_immediate.js タイムアウト すぐに $ ノードタイムアウト_vs_immediate.js すぐに timeout
ただし、I/O ループに移行すると、即時コールバックが常に最初に実行されます
// timeout_vs_immediate.js
const fs = require('fs');
fs.readFile(__ファイル名, () => {
setTimeout(() => {
console.log('タイムアウト');
}, 0);
setImmediate(() => {
console.log('即時');
});
}); $ ノードタイムアウト_vs_immediate.js すぐに タイムアウト $ ノードタイムアウト_vs_immediate.js すぐにSettimeOutよりもタイムアウトセット
メディートの利点は
、タイマーの数に関係なく、SetimmediateがI/Oのタイマーの前に常に実行されることです。
process.nextTick() は非同期 API の一部ですが、図には表示されていないことに気づいたかもしれません。これは、process.nextTick() がイベント ループ テクノロジの一部ではないためです。現在の操作が実行されます。完了後、イベント ループの現在のステージに関係なく、nextTickQueue が実行されます。 ここで、操作は基礎となる C/C++ ハンドラーからの変換として定義され、実行する必要がある JavaScript を処理します。 図によると、どの段階でも process.nextTick() を呼び出すことができます。 process.nextTick() に渡されるすべてのコールバックは、イベント ループの実行が続行される前に実行されます。これにより、再帰的に呼び出すことができるため、いくつかの悪い状況が発生する可能性があります。 process.nextTick() は I/O を「枯渇」させ、イベント ループがポーリング フェーズに入るのを防ぎます。
なぜこの状況が Node.js に含まれているのでしょうか? Node.js の設計哲学では、たとえ非同期である必要がない場合でも、API は常に非同期であるべきであるため、次のスニペット
function apiCall(arg, callback) {を見てください。
if (引数の型 !== '文字列')
return process.nextTick(
折り返し電話、
new TypeError('引数は文字列である必要があります')
);
スニペットは
パラメータをチェックし、正しくない場合はエラーをコールバックに渡します。 API は最近更新され、 process.nextTick() にパラメーターを渡すことができるようになり、コールバックの後に渡されるパラメーターをコールバックへの引数として受け入れることができるため、関数をネストする必要がありません。
私たちが行っていることはエラーをユーザーに返すことですが、これはユーザーのコードの残りの部分の実行を許可する場合に限られます。 process.nexttick()を使用することにより、Apicall()が常にユーザーコードの残りの後にコールバックを実行し、イベントループを続行できるようにします。 これを実現するには、JS コール スタックをアンワインドし、提供されたコールバックをすぐに実行します。これにより、v8 の時点で RangeError: 最大コール スタック サイズを超えたことが発生することなく、process.nextTick() を再帰的に呼び出すことができます。