Event Loop는 JavaScript에서 어떻게 작동합니까?

본격적인 프로덕션 코드를 작성하려면 C++ 및 C와 같은 언어에 대한 심층적인 이해가 필요할 수 있지만 JavaScript는 종종 해당 언어로 수행할 수 있는 작업에 대한 기본적인 이해만으로도 작성할 수 있습니다.

콜백을 함수에 전달하거나 비동기 코드를 작성하는 것과 같은 개념은 종종 구현하기 어렵지 않으므로 대부분의 JavaScript 개발자는 내부에서 진행되는 작업에 대해 덜 신경을 씁니다. 그들은 언어에 의해 깊이 추상화 된 복잡성을 이해하는 데 관심이 없습니다.

JavaScript 개발자로서 내부에서 실제로 발생하는 일과 우리에게서 추상화된 이러한 복잡성의 대부분이 실제로 어떻게 작동하는지 이해하는 것이 점점 더 중요해지고 있습니다. 더 많은 정보에 입각한 결정을 내리는 데 도움이 되며 결과적으로 코드 성능을 크게 높일 수 있습니다.

이 기사는 JavaScript에서 매우 중요하지만 거의 이해되지 않는 개념 또는 용어 중 하나에 중점을 둡니다. 이벤트 루프!.

JavaScript에서 비동기 코드를 작성하는 것은 피할 수 없지만 비동기적으로 실행되는 코드가 실제로 의미하는 이유는 무엇입니까? 즉 이벤트 루프

이벤트 루프가 어떻게 작동하는지 이해하기 전에 먼저 JavaScript 자체가 무엇이며 어떻게 작동하는지 이해해야 합니다!

자바스크립트란 무엇입니까?

계속 진행하기 전에 기본으로 한 걸음 물러나고 싶습니다. 자바스크립트란 과연 무엇인가? JavaScript를 다음과 같이 정의할 수 있습니다.

JavaScript는 높은 수준의 해석된 단일 스레드 비차단, 비동기, 동시 언어입니다.

잠깐, 이게 뭐야? 책 같은 정의? 🤔

그것을 분해하자!

이 기사와 관련된 키워드는 단일 스레드, 비차단, 동시 및 비동기입니다.

단일 스레드

실행 스레드는 스케줄러가 독립적으로 관리할 수 있는 프로그래밍된 명령의 최소 시퀀스입니다. 프로그래밍 언어는 단일 스레드이므로 한 번에 하나의 작업 또는 작업만 수행할 수 있습니다. 이것은 스레드가 중단되거나 중지되지 않고 처음부터 끝까지 전체 프로세스를 실행한다는 것을 의미합니다.

여러 프로세스가 서로 차단하지 않고 여러 스레드에서 동시에 실행될 수 있는 다중 스레드 언어와 다릅니다.

  기계 학습을 시작하는 방법?

JavaScript가 단일 스레드이면서 동시에 차단되지 않는 방법은 무엇입니까?

그러나 차단은 무엇을 의미합니까?

논블로킹

차단에 대한 정의는 없습니다. 단순히 스레드에서 느리게 실행되는 것을 의미합니다. 따라서 비차단이란 스레드에서 느리지 않은 것을 의미합니다.

하지만 잠깐, JavaScript가 단일 스레드에서 실행된다고 말했습니까? 또한 비차단이라고 했는데, 이는 작업이 호출 스택에서 빠르게 실행된다는 것을 의미합니까? 하지만 어떻게??? 타이머를 실행할 때는 어떻습니까? 루프?

안심하다! 우리는 조금 후에 알아낼 것입니다 😉.

병발 사정

동시성은 코드가 둘 이상의 스레드에 의해 동시에 실행되고 있음을 의미합니다.

좋아, 상황이 정말 좋아지고 있어 기이한 이제 어떻게 JavaScript가 단일 스레드이고 동시에 동시적일 수 있습니까? 즉, 둘 이상의 스레드로 코드를 실행합니까?

비동기식

비동기 프로그래밍은 코드가 이벤트 루프에서 실행됨을 의미합니다. 차단 작업이 있으면 이벤트가 시작됩니다. 차단 코드는 기본 실행 스레드를 차단하지 않고 계속 실행됩니다. 차단 코드 실행이 완료되면 차단 작업의 결과를 대기열에 넣고 스택으로 다시 푸시합니다.

그러나 JavaScript에는 단일 스레드가 있습니까? 그러면 스레드의 다른 코드가 실행되도록 하면서 이 차단 코드를 실행하는 것은 무엇입니까?

진행하기 전에 위의 내용을 요약해 보겠습니다.

  • JavaScript는 단일 스레드입니다.
  • 자바스크립트는 차단되지 않습니다. 즉, 느린 프로세스가 실행을 차단하지 않습니다.
  • JavaScript는 동시적입니다. 즉, 동시에 둘 이상의 스레드에서 코드를 실행합니다.
  • JavaScript는 비동기식입니다. 즉, 다른 곳에서 차단 코드를 실행합니다.

그러나 위의 내용이 정확히 합산되지는 않습니다. 어떻게 단일 스레드 언어가 비차단, 동시 및 비동기일 수 있습니까?

조금 더 깊이 들어가 자바스크립트 런타임 엔진인 V8로 내려가 보겠습니다. 아마도 우리가 알지 못하는 숨겨진 스레드가 있을 것입니다.

V8 엔진

V8 엔진은 Google에서 C++로 작성된 JavaScript용 고성능 오픈 소스 웹 어셈블리 런타임 엔진입니다. 대부분의 브라우저는 V8 엔진을 사용하여 JavaScript를 실행하며 인기 있는 노드 js 런타임 환경도 이를 사용합니다.

간단히 말해서 V8은 JavaScript 코드를 받아 컴파일하고 실행하는 C++ 프로그램입니다.

V8은 두 가지 주요 작업을 수행합니다.

  • 힙 메모리 할당
  • 호출 스택 실행 컨텍스트
  돈을 버는 10가지 온라인 설문조사 앱

슬프게도 우리의 의심은 빗나갔다. V8에는 하나의 호출 스택만 있습니다. 호출 스택을 스레드로 생각하세요.

하나의 스레드 === 하나의 호출 스택 === 한 번에 하나의 실행.

이미지 – 해커 정오

V8에는 하나의 호출 스택만 있으므로 JavaScript는 기본 실행 스레드를 차단하지 않고 어떻게 동시 및 비동기적으로 실행됩니까?

간단하면서도 흔한 비동기 코드를 작성하여 함께 알아보고 분석해 보도록 하겠습니다.

JavaScript는 각 코드를 한 줄씩, 한 줄씩 실행합니다(단일 스레드). 예상대로 첫 번째 줄이 여기 콘솔에 인쇄되지만 마지막 줄이 타임아웃 코드 전에 인쇄되는 이유는 무엇입니까? 실행 프로세스가 마지막 줄을 실행하기 전에 타임아웃 코드(블로킹)를 기다리지 않는 이유는 무엇입니까?

스레드가 어느 시점에서든 하나의 단일 작업만 실행할 수 있다고 확신하기 때문에 일부 다른 스레드가 해당 제한 시간을 실행하는 데 도움이 된 것 같습니다.

슬쩍 들여다보자 V8 소스 코드 잠시 동안.

무엇을 기다립니다??!!! V8에는 타이머 기능이 없고, DOM이 없나요? 이벤트가 없나요? 아약스가 없나요?… 예이에스!!!

이벤트, DOM, 타이머 등은 JavaScript 핵심 구현의 일부가 아닙니다. JavaScript는 Ecma 스크립트 사양을 엄격히 준수하며 다양한 버전은 종종 Ecma 스크립트 사양(ES X)에 따라 참조됩니다.

실행 워크플로우

이벤트, 타이머, Ajax 요청은 모두 클라이언트 측에서 브라우저에 의해 제공되며 종종 Web API라고 합니다. 단일 스레드 JavaScript가 비 차단, 동시 및 비동기가 되도록 허용하는 것입니다! 하지만 어떻게?

모든 JavaScript 프로그램, 호출 스택, 웹 API 및 작업 대기열의 실행 워크플로에는 세 가지 주요 섹션이 있습니다.

호출 스택

스택은 마지막으로 추가된 요소가 항상 스택에서 가장 먼저 제거되는 데이터 구조입니다. 마지막으로 추가된 첫 번째 플레이트만 먼저 제거할 수 있는 플레이트의 스택으로 생각할 수 있습니다. 호출 스택은 그에 따라 작업이나 코드가 실행되는 스택 데이터 구조일 뿐입니다.

아래 예를 살펴보겠습니다.

출처 – https://youtu.be/8aGhZQkoFbQ

printSquare() 함수를 호출하면 호출 스택에 푸시되고 printSquare() 함수는 square() 함수를 호출합니다. square() 함수는 스택에 푸시되고, 또한 multiply() 함수를 호출합니다. 곱하기 함수가 스택에 푸시됩니다. 곱하기 함수가 반환되고 스택에 마지막으로 푸시된 것이므로 get이 먼저 해결되고 스택에서 제거된 다음 square() 함수와 printSquare() 함수가 이어집니다.

  실제로 사용하는 앱으로 더 나은 Apple One 번들 구축

웹 API

여기에서 V8 엔진이 처리하지 않는 코드가 실행되어 기본 실행 스레드를 “차단”하지 않습니다. 호출 스택이 웹 API 함수를 만나면 프로세스가 즉시 웹 API로 넘겨져 실행되고 호출 스택이 실행 중에 다른 작업을 수행할 수 있습니다.

위의 setTimeout 예제로 돌아가 보겠습니다.

코드를 실행하면 첫 번째 console.log 라인이 스택으로 푸시되고 거의 즉시 출력을 얻습니다. 타임아웃에 도달하면 타이머는 브라우저에서 처리되며 V8의 핵심 구현의 일부가 아닙니다. 푸시됩니다. 대신 웹 API에 연결하여 다른 작업을 수행할 수 있도록 스택을 비웁니다.

시간 제한이 계속 실행되는 동안 스택은 다음 작업 라인으로 이동하고 마지막 console.log를 실행합니다. 이는 타이머 출력 전에 출력되는 이유를 설명합니다. 타이머가 완료되면 어떤 일이 발생합니다. console.log in 다음 타이머가 마술처럼 호출 스택에 다시 나타납니다!

어떻게?

이벤트 루프

이벤트 루프에 대해 논의하기 전에 먼저 태스크 큐의 기능을 살펴보겠습니다.

시간 초과 예제로 돌아가서 Web API가 작업 실행을 완료하면 자동으로 호출 스택으로 다시 푸시하지 않습니다. 작업 대기열로 이동합니다.

큐는 선입선출 원칙에 따라 작동하는 데이터 구조이므로 태스크가 큐에 푸시되면 동일한 순서로 나옵니다. Web API에 의해 실행되어 Task Queue로 푸시된 작업은 Call Stack으로 돌아가서 결과를 출력합니다.

하지만 기다려. 이벤트 루프는 도대체 무엇입니까???

출처 – https://youtu.be/8aGhZQkoFbQ

이벤트 루프는 작업 대기열에서 호출 스택으로 콜백을 푸시하기 전에 호출 스택이 지워질 때까지 기다리는 프로세스입니다. 스택이 정리되면 이벤트 루프가 트리거되어 사용 가능한 콜백에 대한 작업 대기열을 확인합니다. 만약 있다면 Call Stack으로 push하고 Call Stack이 다시 clear될 때까지 기다린 후 같은 과정을 반복합니다.

출처 – https://www.quora.com/How-does-an-event-loop-work/answer/Timothy-Maxwell

위의 다이어그램은 이벤트 루프와 태스크 큐 사이의 기본 워크플로우를 보여줍니다.

결론

이것은 매우 기본적인 소개이지만 JavaScript의 비동기 프로그래밍 개념은 내부에서 진행되는 작업과 JavaScript가 단일 스레드로 동시 및 비동기적으로 실행될 수 있는 방법을 명확하게 이해할 수 있는 충분한 통찰력을 제공합니다.

JavaScript는 항상 온디맨드이며, 배우고 싶다면 여기를 확인하는 것이 좋습니다. 유데미 과정.