JavaScript がシングルスレッド プログラミング言語であることは、おそらくすでにご存知でしょう。これは、JavaScript が Web ブラウザーまたは Node.js の単一のメイン スレッドで実行されることを意味します。単一のメインスレッドで実行するということは、一度に 1 つの JavaScript コードのみを実行することを意味します。
JavaScript のイベント ループは、メイン スレッドでコードがどのように実行されるかを決定する上で重要な役割を果たします。イベント ループは、コードの実行やイベントの収集と処理などを担当します。また、キューに入れられたサブタスクの実行も処理します。
このチュートリアルでは、JavaScript のイベント ループの基本を学びます。
イベント ループがどのように機能するかを理解するには、3 つの重要な用語を理解する必要があります。
###スタック###キューには、JavaScript によって実行される一連のタスクが含まれます。このキュー内のタスクによって関数が呼び出され、関数がスタックに置かれる可能性があります。キューの処理は、スタックが空の場合にのみ開始されます。キュー内のアイテムは先入れ先出し (FIFO) 原則に従います。これは、最も古いタスクが最初に完了することを意味します。
###ヒープ###基本的に、JavaScript はシングルスレッドであり、一度に 1 つの関数を実行します。この単一関数は
スタックAPI リクエストやタイマーなどの非同期タスクは、後で実行するために
キューに追加されます。 JavaScript エンジンは、アイドル状態のときにキュー内のタスクの実行を開始します。 次の例を考えてみましょう:
リーリー上記のコードを実行した場合にスタックとキューがどのようになるかを見てみましょう。
helloWorld()関数を呼び出してスタックに置きます。
Hello, World!が実行を完了したことがログに記録されるため、スタックから削除されます。次に、
helloTeam() 関数が呼び出され、スタックに配置されます。実行中に、Hello, Team!
をログに記録し、helloperson() を呼び出します。 helloTeam()
の実行はまだ終了していないため、スタック上に残りますが、helloperson() はその上に配置されます。
後入れ先出しの原則により、helloperson()
がすぐに実行されることが規定されています。これにより、Hello, Monty!
がコンソールに記録され、実行が完了し、
がスタックからポップされます。その後、helloTeam()
関数がスタックからポップされ、最終的に byeWorld() に到達します。 さようなら、世界! を記録します。
そしてスタックから消えます。
キューは常に空です。
ここで、上記のコードを少し変更したものを考えてみましょう。
リーリー
ここで行った唯一の変更は、
を使用することです。ただし、タイムアウトはゼロに設定されています。したがって、
Hello, Monty!が
Bye, World! の前に出力されることが期待されます。イベント ループの仕組みを理解していれば、なぜこれが起こらないのかが理解できるでしょう。
helloTeam() がスタックにプッシュされると、setTimeout() メソッドが検出されます。ただし、setTimeout()
の helloperson()
への呼び出しはキューに入れられ、実行する同期タスクがなくなると実行されます。
byeWorld()
への呼び出しが完了すると、イベント ループは保留中のタスクがないかキューをチェックし、helloperson()
への呼び出しを見つけます。この時点で、関数が実行され、
がコンソールに記録されます。
これは、setTimeout()
に指定したタイムアウト期間がコールバックの実行時間を保証するものではないことを示しています。これは、コールバックが実行される最小時間です。
Web ページの応答性を維持する
JavaScript の興味深い特徴は、関数が完了するまで実行されることです。これは、関数がスタック上にある限り、イベント ループはキュー内の他のタスクを処理したり、他の関数を実行したりできないことを意味します。
これにより、ユーザー入力の処理や DOM 関連の変更など、他の操作を実行できなくなり、Web ページが「ハング」する可能性があります。指定された範囲内の素数の数を求める次の例を考えてみましょう:
関数では、
startから
end までの数値を反復処理します。各数値について、isPrime()
関数を呼び出して、それが素数かどうかを確認します。 isPrime()
関数自体には、2
から Math.sqrt(num)
までを実行する for
ループがあり、数値がは素数です。
<p>查找给定范围内的所有素数可能需要一段时间,具体取决于您使用的值。当浏览器进行此计算时,它无法执行任何其他操作。这是因为 <code>listPrimesInRange()
函数将保留在堆栈中,浏览器将无法执行队列中的任何其他任务。
现在,看一下以下函数:
function listPrimesInRangeResponsively(start) { let next = start + 100,000; if (next > end) { next = end; } for (let num = start; num <= next; num++) { if (isPrime(num)) { primeNumbers.push(num); } if (num == next) { percentage = ((num - begin) * 100) / (end - begin); percentage = Math.floor(percentage); progress.innerText = `Progress ${percentage}%`; if (num != end) { setTimeout(() => { listPrimesInRangeResponsively(next + 1); }); } } if (num == end) { percentage = ((num - begin) * 100) / (end - begin); percentage = Math.floor(percentage); progress.innerText = `Progress ${percentage}%`; heading.innerText = `${primeNumbers.length - 1} Primes Found!`; console.log(primeNumbers); return primeNumbers; } } }
这一次,我们的函数仅在批量处理范围时尝试查找素数。它通过遍历所有数字但一次仅处理其中的 100,000 个来实现这一点。之后,它使用 setTimeout()
触发对同一函数的下一次调用。
setTimeout()
被调用而没有指定延迟时,它会立即将回调函数添加到事件队列中。
下一个调用将被放入队列中,暂时清空堆栈以处理任何其他任务。之后,JavaScript 引擎开始在下一批 100,000 个数字中查找素数。
尝试单击此页面上的计算(卡住)按钮,您可能会收到一条消息,指出该网页正在减慢您的浏览器速度,并建议您停止该脚本。 p>
另一方面,单击计算(响应式)按钮仍将使网页保持响应式。
在本教程中,我们了解了 JavaScript 中的事件循环以及它如何有效地执行同步和异步代码。事件循环使用队列来跟踪它必须执行的任务。
由于 JavaScript 不断执行函数直至完成,因此进行大量计算有时会“挂起”浏览器窗口。根据我们对事件循环的理解,我们可以重写我们的函数,以便它们批量进行计算。这允许浏览器保持窗口对用户的响应。它还使我们能够定期向用户更新我们在计算中取得的进展。
以上がJavaScript のイベント ループを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。