> For the complete documentation index, see [llms.txt](https://bumkeyy.gitbook.io/bumkeyy-code/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bumkeyy.gitbook.io/bumkeyy-code/javascript/javascript-event-loop-explained.md).

# \[번역] JavaScript Event Loop Explained

"JavaScript는 어떻게 비동기로 동작하고 단일 스레드 인가요?" 에 대한 짧은 답변으로는 JavaScript 언어가 단일 스레드이며, 비동기 동작은 JavaScript 언어 자체의 일부가 아니라 브라우저(또는 프로그래밍 환경)의 코어 JavaScript 언어 환경에서 구축되며 브라우저 API를 통해 엑세스 됩니다.

좀 더 자세한 답변을 위해 2 개의 코드 스니펫을 사용하겠습니다.

## 기본 구조 (Basic Architecture)

![Overview of major components in a browser](/files/-M6z8aHzJEQaIduZiUN8)

* **힙 (Heap)** - 객체는 대부분 구조화되지 않은 큰 메모리 영역인 힙에 할당됩니다.
* **스택 (Stack)** - JavaScript 코드 실행을 위해 제공되는 단일 스레드를 의미합니다. 함수 호출은 프레임 스택을 형성합니다.(자세한 내용은 아래 참조)
* **브라우저 혹은 웹 API (Browser or Web API)**&#xB294; 웹 브라우저 안에 내장되어 있으며 브라우저 및 주변 퓨터 환경에서 데이터를 노출하고 유용하고 복잡한 작업을 수행할 수 있습니다. **JavaScript 언어 자체의 일부가 아니라 코어 JavaScript 언어 위에 구축되어 JavaScript 코드에서 사용할 수 있는 추가 기능을 제공합니다.** 예를 들어, Geolocation API는 위치 데이터 검색을 위한 간단한 JavaScript 구성을 제공해서 Google 지도에서 위치를 플롯할 수 있습니다. 백그라운드에서 실제로 장치의 GPS 하드웨어(또는 위치데이터를 결정하는데 사용하는 모든 것)와 통신하고 데이터를 검색하여 브라우저 환경으로 돌려 보내기 위해 복잡한 하위 레벨 코드(예: C++)를 사용하고 있습니다. 하지만 우리의 코드에서 이 복잡성은 API에 의해 추상화 됩니다.

## Code Snippet 1 : Intrigue the mind

```javascript
function main(){
  console.log('A');
  setTimeout(
    function display(){ console.log('B'); }
  ,0);
	console.log('C');
}
main();
//	Output
//	A
//	C
//  B
```

여기에는 콘솔에 'A'와 'C'를 출력하는 2 개의 `console.log` 명령어를 가진 `main` 함수가 있습니다. 두 명령어 사이에 0ms 대기시간으로 콘솔에 'B'를 출력하는 `setTimeout` 호출이 있습니다.&#x20;

![Inner working during the execution](/files/-M6zCI5kHIUbfcV8wAES)

1. `main` 함수 호출은 먼저 스택으로(프레임으로) 푸시됩니다. 그 다음 브라우저는 기본 함수의 첫 번째 명령문인 `console.log('A')`를 스택으로 푸시합니다. 이 명령문이 실행되고 완료되면 해당 프레임이 튀어 나옵니다. 콘솔에 알파벳 A가 출력됩니다.
2. 다음 명령문 (콜백 `exec()` 및 0ms 대기 시간이 있는 `setTimeout()`)이 호출 스택으로 푸시되고 실행이 됩니다. `setTimeout` 함수는 브라우저 API를 이용하여 제공된 함수의 콜백을 지연시킵니다. 브라우저로 이동이 (타이머에 대한) 완료되면  프레임 (`setTimeout` 포함)이 튀어 나옵니다.
3. exec() 함수의 콜백을 위해 브라우저에서 타이머가 실행되는 동안 `console.log('C')`가 스택으로 푸시됩니다. 이때 정해진 지연이 0ms이므로 브라우저가 (이상적으로) 수신하자마자 콜백이 메시지 큐에 추가됩니다.
4. `main` 함수에서 마지막 명령문을 실행한 후 `main()` 프레임이 호출 스택에서 튀어나와 스택이 비워집니다. 브라우저가 큐에서 호출 스택으로 메시지를 푸시하려면 먼저 호출 스택이 비어있어야 합니다. 따라서 `setTimeout()` 에 제공된 지연 시간이 0초여도 `exec()` 에 대한 콜백은 호출 스택의 모든 프레임 실행이 완료될 때까지 기다려야 합니다.
5. 이제 콜백 `exec()` 가 호출 스택으로 푸시되어 실행됩니다. 알파벳 B가 콘솔에 출력됩니다. 이것이 JavaScript의 이벤트 루프입니다.

> 따라서 `setTimeout(function, delayTime)` 의 지연 매개 변수는 함수가 실행 된 후 정확한 시간 지연을 보장하지 않습니다. 특정 상황에서 함수가 실행될 최소 대기 시간을 나타냅니다.

## Code Snippet 2 : Deeper Understanding

```javascript
function main(){
  console.log('A');
  setTimeout(
    function exec(){ console.log('B'); }
  , 0);
  runWhileLoopForNSeconds(3);
  console.log('C');
}
main();
function runWhileLoopForNSeconds(sec){
  let start = Date.now(), now = start;
  while (now - start < (sec*1000)) {
    now = Date.now();
  }
}
// Output
// A
// C
// B
```

![](/files/-M6zGRx_OagQHQbyUqb-)

* `runWhileLoopForNSeconds()` 함수는 이름처럼 정확하게 수행합니다. 호출된 시간부터 경과 된 시간이 인수로 전달받은 초수와 같은지 계속 확인합니다. 기억해야할 주요 사항은 `while` 루프(다른 것들과 마찬가지로)는 호출 스택에서 실행이 발생하고 브라우저 API를 사용하지 않는 차단 문이라는 점입니다. 따라서 실행이 끝날 때까지 모든 후속 명령문을 차단합니다.
* 따라서 위 코드의 `setTimeout`의 지연 시간이 0초이고 `while` 루프가 3초 동안 실행되더라도 `exec()` 콜백은 메시지 큐에서 멈춰있습니다. `while` 루프는 3초가 경과할 때 까지 호출 스택(단일 스레드)에서 계속 실행됩니다. 그리고 호출 스택이 비워지면 콜백 `exec()`이 호출 스택으로 이동하여 실행됩니다.
* `setTimeout`의 지연 인수는 타이머가 지연을 완료한 후 실행 시작을 보장하지 않습니다. 지연의 최소 시간으로 사용됩니다.
