Flash の「エラスティック レーストラック」はブラウザから継承されました。もちろん、ブラウザの世界ではそうは呼ばず、イベント ループと呼んでいます。
JavaScript のイベント ループの歴史は、Netscape でのプログレッシブ GIF および JPEG レンダリングから始まりました。プログレッシブ レンダリング (部分的に読み込まれたコンテンツの描画) には、Netscape が非同期ダウンロード レンダリング エンジンを実装する必要がありました。Brendan Eich が JavaScript を実装したとき、この非同期イベント ループはすでに存在していました。そのため、別のレイヤーを追加するのはかなり簡単な作業でした。
したがって、ブラウザのイベント ループは次のようになります。
Event loop
┌──────────┐
│ │
│ │
│ ▼
│ check if there's any new ───────▶ parse data
│ data on the network │
│ │ │
│ ▼ │
│ check if we need to execute ◀─────────┘
│ any javascript ──────────────────▶ execute
│ │ javascript
│ ▼ │
│ check if we need to ◀────────────────┘
│ redraw the page ──────────────▶ redraw page
│ │ │
│ │ │
└────◀─────┴─────────────────◀─────────────────┘
彼らが言うように、残りは歴史です。Microsoft が JavaScript をコピーしたとき、Netscape との互換性を維持するために、イベント ループを複製する必要がありました。そのため、Netscape および IE との互換性を維持するために、誰もが同じことをしなければなりませんでした。
JavaScript には手動でイベント ループに再帰する機能がないことに注意してください (たとえば、tcl などの一部の言語では実行できます)。そのため、ブラウザは、実行する JavaScript がなくなるまで待機してから、ページを再描画する必要があります。スクリプトが終了するまで、ページの再描画を強制することはできません。
このため、要素の幅や高さなどの計算された値を作成直後に読み取ろうとすると、間違った値が返されることがあります。ブラウザーはまだそれらを描画していません。ページの再描画後にコードを実行する必要がある場合の回避策はsetTimeout
、タイムアウト値を 0 にして を使用し、ブラウザがイベント ループを 1 回実行できるようにすることです。
追加の詳細:
高価なリフローを引き起こす例外的な条件が 1 つあります。リフローは、ページ レイアウトを計算するブラウザーであることに注意してください。通常、ブラウザが変更されたページを描画する必要がある場合にトリガーされます。
ページ内の何かが変更されると、リフロー計算がキューに入れられ、すぐには実行されません。上記の説明のように、リフローは JavaScript 実行の最後にのみ実行されます。しかし、ブラウザーがすぐにリフロー計算を実行する原因となるケースが 1 つあります。それは、幅や高さなどの計算値を読み込もうとした場合です。
詳細については、この関連する質問を参照してください: DOM 環境でリフローが発生するのはいつですか?