아마도 JavaScript가 단일 스레드 프로그래밍 언어라는 것을 이미 알고 계실 것입니다. 이는 JavaScript가 웹 브라우저 또는 Node.js의 단일 기본 스레드에서 실행된다는 것을 의미합니다. 단일 메인 스레드에서 실행한다는 것은 한 번에 하나의 JavaScript 코드만 실행한다는 것을 의미합니다.
JavaScript의 이벤트 루프는 메인 스레드에서 코드가 실행되는 방식을 결정하는 데 중요한 역할을 합니다. 이벤트 루프는 코드 실행, 이벤트 수집 및 처리 등을 담당합니다. 또한 대기 중인 하위 작업의 실행도 처리합니다.
이 튜토리얼에서는 JavaScript의 이벤트 루프에 대한 기본 사항을 배웁니다.
이벤트 루프의 작동 방식을 이해하려면 세 가지 중요한 용어를 이해해야 합니다.
호출 스택은 단순히 함수의 실행 컨텍스트를 추적하는 함수 호출 스택입니다. 스택은 LIFO(후입선출) 원칙을 따릅니다. 즉, 가장 최근에 호출된 함수가 가장 먼저 실행됩니다.
큐에는 JavaScript가 실행하는 일련의 작업이 포함되어 있습니다. 이 대기열의 작업으로 인해 함수가 호출될 수 있으며, 함수는 스택에 배치됩니다. 대기열 처리는 스택이 비어 있을 때만 시작됩니다. 대기열의 항목은 FIFO(선입선출) 원칙을 따릅니다. 즉, 가장 오래된 작업이 먼저 완료됩니다.
힙은 기본적으로 객체가 저장되고 할당되는 넓은 메모리 영역입니다. 주요 목적은 함수에서 사용할 수 있는 데이터를 스택에 저장하는 것입니다.
기본적으로 JavaScript는 단일 스레드이며 한 번에 하나의 기능을 실행합니다. 이 단일 함수는 스택에 배치됩니다. 함수에는 스택의 더 높은 위치에 배치되는 다른 중첩 함수도 포함될 수 있습니다. 스택은 LIFO 원칙을 따르므로 가장 최근에 호출된 중첩 함수가 먼저 실행됩니다.
API 요청이나 타이머와 같은 비동기 작업은 나중에 실행하기 위해 queue에 추가됩니다. JavaScript 엔진은 유휴 상태일 때 대기열에 있는 작업 실행을 시작합니다.
다음 예를 고려해보세요:
으아악위 코드를 실행하면 스택과 큐가 어떻게 보이는지 살펴보겠습니다.
helloWorld()
함수를 호출하고 스택에 넣습니다. helloWorld()
函数并将其放入堆栈中。它记录 Hello, World! 完成其执行,因此它被从堆栈中取出。接下来调用 helloTeam()
函数并将其放入堆栈中。在执行过程中,我们记录 Hello, Team! 并调用 helloPerson()
。 helloTeam()
的执行还没有完成,所以它停留在堆栈上,而 helloPerson()
Hello, World!
helloTeam()
함수가 호출되어 스택에 배치됩니다. 실행하는 동안 Hello, Team!helloPerson()
现在执行。这会将 Hello, Monty! 记录到控制台,从而完成其执行,并且 helloPerson()
将从堆栈中取出。之后 helloTeam()
函数就会出栈,我们最终到达 byeWorld()
을 기록하고 helloPerson()
을 호출합니다. helloTeam()
의 실행이 아직 완료되지 않았으므로 스택에 남아 있고 helloPerson()
이 그 위에 배치됩니다.
후입선출 원칙은 helloPerson()
이 지금 실행된다는 것을 규정합니다. 그러면
가 콘솔에 기록되어 실행이 완료되고 helloPerson()
이 스택에서 제거됩니다. 그런 다음 helloTeam()
함수가 스택에서 튀어나오고 마침내 byeWorld()
에 도달합니다.
그러면 스택에서 사라집니다.
대기열은 항상 비어 있습니다. setTimeout()
이제 위 코드를 약간 변형해 보겠습니다.
으아악
여기서 변경한 유일한 사항은 을 사용하는 것입니다. 그러나 시간 초과는 0으로 설정되었습니다. 따라서 Hello, Monty!
가 helloTeam()
入栈时,遇到setTimeout()
方法。但是,setTimeout()
中对 helloPerson()
Bye, World!
byeWorld()
的调用完成,事件循环将检查队列中是否有任何挂起的任务,并找到对 helloPerson()
helloTeam()
이 스택에 푸시되면 메서드가 발생합니다. 그러나 의 helloPerson()
에 대한 호출은 대기열에 들어가고 실행할 동기화 작업이 없으면 실행됩니다.
1번 setTimeout()
에 전화가 걸립니다. 이 시점에서 함수를 실행하고
이는
에 제공한 제한 시간이 콜백 실행을 보장하는 시간이 아님을 나타냅니다. 콜백이 실행되는 최소 시간입니다.웹페이지의 반응성을 유지하세요
listPrimesInRange()
函数中,我们迭代从 start
到 end
的数字。对于每个数字,我们调用 isPrime()
函数来查看它是否是素数。 isPrime()
函数本身有一个 for
循环,该循环从 2
到 Math.sqrt(num)
JavaScript의 흥미로운 기능은 완료될 때까지 함수를 실행한다는 것입니다. 즉, 함수가 스택에 있는 한 이벤트 루프는 대기열의 다른 작업을 처리하거나 다른 함수를 실행할 수 없습니다.
查找给定范围内的所有素数可能需要一段时间,具体取决于您使用的值。当浏览器进行此计算时,它无法执行任何其他操作。这是因为 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!