JavaScript の イベントループ
( event loop) は以下のように動作します。
JavaScript の非同期処理は、イベントループを基盤に以下の2種類に分類されます:
分類 | 代表的な例 | 実行順序の優先度 |
---|---|---|
マイクロタスク | Promise.then, MutationObserver | コールスタックが空の直後に実行 |
マクロタスク | setTimeout, setInterval, I/O | マイクロタスクがすべて完了した後に実行 |
マイクロタスクは「現在のコールスタックの処理が完了した直後」に実行されます。
優先度が高く、以下が該当します:
マクロタスクは「マイクロタスクがすべて処理された後」に実行されます。
以下が該当します:
setTimeout のコールバックは非同期処理といえますが、マクロタスクに分類されます。 指定された遅延時間が経過しても、マイクロタスクが優先されるため、コールスタックやマイクロタスクが処理されるまで実行されません。
console.log('Start');
setTimeout(() => {
console.log('setTimeout'); // マクロタスク
}, 0);
Promise.resolve().then(() => {
console.log('Promise'); // マイクロタスク
});
const observer = new MutationObserver(() => {
console.log('MutationObserver'); // マイクロタスク
});
const target = document.createElement('div');
observer.observe(target, { attributes: true });
target.setAttribute('data-test', 'value');
console.log('End');
// Start
// End
// Promise
// MutationObserver
// setTimeout
重い同期処理(例: 長いループ)は、非同期処理を遅延させます。
コールスタックがすべて処理されるまで、マイクロタスクもマクロタスクも実行されません。 最小遅延時間:setTimeout(fn, 0) の実行は「即時実行」ではなく、タイマーの最小遅延時間(通常4ms)に依存します。
マイクロタスクの過剰な使用:大量のマイクロタスクが登録されると、マクロタスクが遅延し、UI 更新や I/O 処理が滞る可能性があります。