イベントループはあなたの JavaScript を単一スレッドで実行するため、長時間かかる同期的なものは何であれそれをブロックします — そしてブロックされている間、Node は他のいかなるリクエスト、タイマー、コールバックも処理しません。ブロッキングはほぼ常に CPU バウンドの処理または *Sync API であり、適切に await された非同期 I/O では決してありません。
*Sync) API — fs.readFileSync、fs.writeFileSync、child_process.execSync、zlib.gzipSync。これらは libuv に処理を渡す代わりにその場で待機します。map/sort/filter、行列計算、画像/動画処理、巨大な構造のパース/シリアライズ。JSON.parse / JSON.stringify — 同期的で O(n)。数 MB のペイロードはパース全体の間ループをフリーズさせます。crypto.pbkdf2Sync、bcrypt の同期モード、メインスレッドでの大きなバッファのハッシュ化。while (true)、無制限の再帰、要素ごとに処理を伴う数百万要素に対する for。// これらはすべてループをブロックします — その間、他のリクエストは一切処理されません:
const data = fs.readFileSync("big.json"); // 同期 I/O
const obj = JSON.parse(hugeString); // 大きなパース
const hash = crypto.pbkdf2Sync(pw, salt, 1e6, 64, "sha512"); // 同期暗号処理
for (let i = 0; i < 1e9; i++) { /* CPU */ } // きついループ
CPU 処理を
async関数で包んでも助けになりません —asyncはawaitでのみ制御を譲ります。同期的な本体は依然としてループスレッド上で最後まで実行されます。
perf_hooks.monitorEventLoopDelay() や blocked-at のようなライブラリで測定します。遅延の増加は何かがスレッドを占有していることを意味します。node --prof、clinic doctor/clinic flame、Chrome DevTools の CPU プロファイルでホットな同期フレームを見つけます。*Sync 呼び出しの非同期版を使います (fs.promises.readFile、crypto.pbkdf2、zlib.gzip)。worker_threads プール、子プロセス、または外部のキュー/サービスに移します。setImmediate/await で分割し、バッチの合間にループが息をつけるようにします。const { Worker } = require("node:worker_threads");
// 高コストなハッシュ処理をオフロードして、ループが応答性を保つようにします。
const worker = new Worker("./hash-worker.js", { workerData: { pw, salt } });
Node では、1 つのブロッキング呼び出しが、それを引き起こしたリクエストだけでなく、すべての同時クライアントを罰します — レイテンシが急増し、ヘルスチェックがタイムアウトし、プロセスは負荷下で「ハング」しているように見えます。面接官がこれを尋ねるのは、具体的なブロッカー (*Sync、大きな JSON.parse、同期暗号処理、ReDoS、CPU ループ) を挙げられるか、イベントループ遅延のツールで検出できるか、そして非同期化やワーカースレッドへのオフロードで修正できるかを見るためです。これは本番環境で最も一般的な Node のパフォーマンス障害です。
ジュニアからシニアまで、詳細な回答付きのIT面接質問ライブラリ。
寄付する