JSイベントループの深い理解
- 1540単語
- 8分
- 04 Jul, 2024
JavaScriptでは、イベントループ(Event Loop)機構を理解することが非同期プログラミングをマスターする鍵です。本文では、JavaScriptのイベントループ機構およびその中で使用されるさまざまな関数について、setTimeout
、setInterval
、Promise
、MutationObserver
、requestAnimationFrame
、requestIdleCallback
を含めて詳しく説明します。それらの違い、使用シーン、およびパフォーマンスへの影響に重点を置いて解説します。
イベントループ(Event Loop)の概念
JavaScriptはシングルスレッドであり、同時に1つのタスクしか実行できません。非同期操作を効率的に処理するために、JavaScriptはタスクキュー機構を導入しています。タスクキューはマクロタスク(Macro Task)とマイクロタスク(Micro Task)に分けられます。
マクロタスク
マクロタスクは、setTimeout
、setInterval
、I/O操作、イベント処理などの非同期操作を含みます。各イベントループは1つのマクロタスクを実行し、その後すべてのマイクロタスクを実行します。
マイクロタスク
マイクロタスクは、Promise
のコールバック関数やMutationObserver
などの小さな非同期操作を含みます。マイクロタスクは通常、現在のマクロタスクの終了後すぐに実行され、マクロタスクよりも優先度が高いです。
イベントループの動作原理
イベントループのプロセスは次のとおりです:
- 実行スタックの同期タスクをすべて実行します。
- マイクロタスクキュー内のすべてのタスクをチェックして実行します。
- 1つのマクロタスクを実行します。
- 上記のステップを繰り返します。
setTimeoutとsetInterval
setTimeout
setTimeout
は、指定された時間後に関数を実行するために使用されます。その基本的な構文は以下のとおりです:
1setTimeout(function, delay, [arg1, arg2, ...]);
function
:実行する関数。delay
:遅延時間(ミリ秒)。[arg1, arg2, ...]
:関数に渡す引数(任意)。
例
1setTimeout(() => {2 console.log("This will be logged after 2 seconds");3}, 2000);
setInterval
setInterval
は、指定された時間間隔で関数を繰り返し実行するために使用されます。その基本的な構文は以下のとおりです:
1setInterval(function, interval, [arg1, arg2, ...]);
function
:実行する関数。interval
:間隔時間(ミリ秒)。[arg1, arg2, ...]
:関数に渡す引数(任意)。
例
1setInterval(() => {2 console.log("This will be logged every 2 seconds");3}, 2000);
違いと使用シーン
setTimeout
は、一度だけ遅延して実行する必要があるタスクに適しています。例えば、遅延提示。setInterval
は、定期的に実行する必要があるタスクに適しています。例えば、データの定期的な更新。
パフォーマンスへの影響
setTimeout
とsetInterval
はタスクをマクロタスクキューに追加するため、他のタスクの実行によって遅延が発生する可能性があります。setInterval
の不適切な使用は、パフォーマンス問題を引き起こす可能性があります。例えば、メインスレッドをブロックし、ページの応答速度に影響を与えることがあります。
PromiseとMutationObserver
Promise
Promise
は非同期操作を処理するために使用され、より簡潔な構文と強力な機能を提供します。その基本的な使い方は以下のとおりです:
1let promise = new Promise((resolve, reject) => {2 // 非同期操作3 if (/* 成功 */) {4 resolve(value);5 } else {6 reject(error);7 }8});9
10promise.then(value => {11 // 成功時のコールバック12}).catch(error => {13 // 失敗時のコールバック14});
例
1let promise = new Promise((resolve, reject) => {2 setTimeout(() => {3 resolve("Success");4 }, 1000);5});6
7promise.then((value) => {8 console.log(value); // "Success"と出力されます9});
MutationObserver
MutationObserver
は、DOMツリーの変化を監視し、変化が発生したときにコールバック関数を実行するために使用されます。その基本的な使い方は以下のとおりです:
1let observer = new MutationObserver(callback);2
3observer.observe(targetNode, config);
callback
:DOM変化時に実行するコールバック関数。targetNode
:監視対象のDOMノード。config
:監視オプション。
例
1let targetNode = document.getElementById("target");2let config = { attributes: true, childList: true, subtree: true };3
4let callback = function (mutationsList, observer) {5 for (let mutation of mutationsList) {6 console.log(mutation);7 }8};9
10let observer = new MutationObserver(callback);11observer.observe(targetNode, config);
違いと使用シーン
Promise
は非同期操作の結果を処理するのに適しています。例えば、APIリクエスト。MutationObserver
はDOMの変化を監視するのに適しています。例えば、動的コンテンツの更新。
パフォーマンスへの影響
Promise
のコールバック関数はマイクロタスクキューに追加され、マクロタスクよりも優先度が高いです。MutationObserver
のコールバック関数もマイクロタスクキューに追加され、DOMの変化をリアルタイムに監視するのに適しています。
requestAnimationFrameとrequestIdleCallback
requestAnimationFrame
requestAnimationFrame
は、次のリペイントの前に関数を実行するために使用され、通常、高性能なアニメーションを実現するために使用されます。その基本的な構文は以下のとおりです:
1requestAnimationFrame(callback);
callback
:次のリペイントの前に実行する関数。
例
1function animate() {2 // アニメーションの状態を更新する3 requestAnimationFrame(animate);4}5requestAnimationFrame(animate);
使用シーン
requestAnimationFrame
は、各フレームで更新が必要なタスクに適しています。例えば、アニメーションやゲームのレンダリング。
パフォーマンスへの影響
requestAnimationFrame
は画面のリフレッシュレートに基づいて実行頻度を自動調整するため、不要な計算を避け、パフォーマンスを向上させます。setInterval
と比較して、requestAnimationFrame
はより効率的でスムーズです。
requestIdleCallback
requestIdleCallback
は、ブラウザがアイドル状態のときに関数を実行するために使用されます。その基本的な構文は以下のとおりです:
1requestIdleCallback(callback, [options]);
callback
:ブラウザがアイドル状態のときに実行する関数。[options]
:オプションの設定オブジェクト。
例
1requestIdleCallback(() => {2 console.log("This will be logged when the browser is idle");3});
使用シーン
requestIdleCallback
は、ユーザー体験に影響を与えない形で低優先度のタスクを実行するのに適しています。例えば、データのプレロードや分析タスク。
パフォーマンスへの影響
requestIdleCallback
はブラウザがアイドル状態のときにタスクを実行するため、メインスレッドをブロックせず、ユーザー体験を向上させます。- 低優先度、緊急でないタスクのスケジューリングに適しています。
まとめ
この記事を通して、JavaScriptのイベントループの概念およびその中で使用されるさまざまなメソッドの違い、使用シーン、およびそれらがパフォーマンスに与える影響について理解しました。これらのメソッドを適切に使用することで、フロントエンドアプリケーションのパフォーマンスとユーザー体験を向上させることができます。