# 강남_A_Day11 리뷰 레포트
### 참석자
- 권혁, 나영균, 이상아
## 1. 코드 동작 이해
```
- 가장 많은 체크포인트를 구현한 사람의 코드의 동작 원리를
이해하는 과정에서 발생한 건설적인 대화를 기록, 정리합니다.
```
* `runSync(id)`
1. 처음에 현재 시간을 구한다 `const date1 = new Date().getTime();` . (실제 ms 단위의 시간을 얻으 수 있다)
2. `while loop`이 처음 실행한 시간과 `while loop`안에서 확인하는 시간차가 2000ms 가 되기 전까지 loop을 벗어 날 수 없다.
3. `while loop`을 벗어날 수 없기때문에 callstack에서 빠지지 않고 sync작업이 될 수 있다.
* `executeEventQueue()`
1. `setIntverval`로 콜백을 등록하여 계속해서 작업을 실행한다.
2. 위의 작업은 계속해서 콜스택과 이벤트큐를 확인하고 콜스택이 비어있고 이벤트큐가 차있다면 이벤트큐의 task를 콜스택으로 보내준다.
* `executeCallStack()`
1. `executeCallStack()`은 콜스택에 있는 태스크가 있으면 스택의 가장 위의 작업을 꺼내어 수행한다.
- `executeEventQueue`와 `executeCallStack`도 자체적으로 callstack의 길이를 체크하기 때문에 작업을 수행한 후 `pop`한다.
2. 만약 콜스택의 길이가 0이된다면 카운트다운을 시작한다.
3. 계속해서 콜스택의 길이가 0이고 카운트다운이 5000ms가 된다면 `process.exit()`을 실행하여 프로그램을 종료한다.
4. 그리고 1번을 `setInterval`로 callback으로 등록하여 계속해서 수행한다.
## 2. 코드 동작 개선
```
- 다함께 하나 이상의 체크포인트를 구현하기 위해
시도했던 문제 해결의 과정을 정리합니다.
- 학습정리의 `스스로 확인할 사항`에 대해 고민한 내용을 공유하고
서로의 코드를 더 발전시킬 수 있는 형태로 내용을 기록합니다.
```
### 권혁
- callstack을 모니터링하면서 작업을 수행하는 기능을 구현하기 위해서 setTimeout()을 사용하면 된다는 사실을 알게 되었다.
- 5초 동안 idle 이면 종료하는 기능을 구현하기 위해 .bind(null, args) 형태로 recursive call 을 이용하면 된다는 사실을 알게 되었다.
### 나영균
- executeCallStack()함수 내부로직을 setInterval로 콜백으로 등록하기 때문에 한번은 바로 실행하지 않아서 내부로직을 내부에서 함수로 감싼후 실행후 setInterval로 등록하였다
- 이 부분을 내부로직을 그대로 놓고 setTimeout으로 recursive하게 구현했다면 조금 더 클린코드를 구현할 수 있을것으로 예상된다.
- 처음에 시간을 제대로 점검하지 않고 실행하였을때 순서대로 작동하는 것을 보고 완료했구나라고 착각하였다.
- 각각의 실행시간을 로그해 보았고 runSync들은 제대로 작동하였으나 setTimeout으로 runSync를 등록하는 부분에서 12초가 구현되지 않는 것과 프로그램 종료가 id 4로 부터 5초가 아니라는 것을 알게되었다
- 각각이 setTimeout이 등록되는 시간과 콜스택에 등록되는 로직을 정확히 이해하도록 노력하였다.
### 이상아
* `executeEventQueue(call, event)`, `executeCallStack(call)` 에서 각 `queue`와 `stack`에 새로운 값이 들어오는가를 리스닝하기 위해, `setInterval()`을 사용할 수 있다는 것을 알게되었다.
* `.shift()` 함수를 사용하면 `[0, 1, 2, 3, 4]` 에서 `0`을 빼낼 수 있다는 사실을 알게되었다.
## 3. Consideration
```
- 학습정리의 `다같이 확인할 사항`에 대해 충분히 토의하고 그 과정을 일목요연하게 정리합니다.
```
### 실제 call stack과 event queue동작을 충분히 이해하고, 이를 코드로 구현한 것인지 확인한다.
#### 권혁
- runSync(): Date.now()를 사용하여 50,000,000 loop를 계속 실행하면서 Date.now()를 다시 호출하여 2초를 계산한다.
- executeCallStack(): callstack에 있는 함수들을 pop하여 순차적으로 실행함
- executeEventQueue(): callstack이 비어있는지 확인하고 callstack이 empty 인 경우, eventQueue에 있는 함수들을 하나씩 callstack에 push 한다.
#### 나영균
- 처음에 runSync 1과 2가 콜스택에 저장되어 있고 3을 push하는 과정을 보고 2가 3을 호출하는 것으로 착각하여 3이 가장 먼저 실행되야 한다고 착각했었다. 3은 사실 다른줄의 코드같은 개념으로 1다음으로 호출 되는 것이였다.
- sync 1과 2가 콜스택에서 해소가 되고 3을 콜스택으로 보내어 처리를 하고 콜스택이 비워진 상태가 되면 executeEventQueue가 async 작업들을 콜스택으로 보내어 실행된다.
- 그 후 setTimeout으로 web api쪽으로 보내져있던 sync4가 콜스택에 등록되어 실행되고 콜스택이 비워진 시간이 카운트 다운이 시작된다.
- 카운트 다운이 5초가 된 순간 process.exit()되고 sync5는 queue에 등록되기전에 종료된다.
#### 이상아
* `executeEventQueue`: eventqueue를 구현했다. event queue는 call stack이 비어있는지를 계속 모니터링하며, call stack이 비어있으면 event queue의 내용을 call stack으로 옮긴다
* `executeCallStack` : call stack에 있는 내용을 역순으로 실행하게 구현하였다.
### 자바스크립트 비동기에 대해서 이해하기 위해서, call stack과 event queue, event loop에 대해서 글로 정리한다.
#### 권혁
* 실행되는 모든 함수는 호출되는 순간 callstack에 push되어 실행되고 실행을 종료하는 순간 callstack에서 pop 된다.
* setTimeout(), AJAX, 기타 시간이 걸리는 작업들을 asynchronous하게 callback 형태로 함수를 만들어서 호출하면,
* setTimeout(), AJAX 등의 함수도 callstack에 push 되어 처리된다. 이때 그 함수 내부에 선언된 callback 함수는 Web API 와 같이 해당 작업이 종료될 때 실행되는 함수이므로 callback 함수가 호출되는 상황이 올 때 까지 대기한다.
* callback 함수가 호츌되는 시점이 되면, callback 함수는 event queue 에 추가된다.
* event loop는 callstack을 모니터링하면서 callstack이 empty 일때 event queue 맨앞에 있는 함수를 callstack에 push 하여 처리한다.
#### 나영균
- **콜스택**(**Call stack**)은 함수가 호출될때마다 내부에서 다른 함수를 호출하면 새로 호출된 함수들이 쌓이게 되고 새로 호출한 함수를 모두 실행하여 콜스택에서 제거하면 호출했던 코드로 돌아가 하던 실행을 마저하는 프로세스에서 실행중인 함수들이 호출된 역순으로 일을 마치는 순서를 말한다.
- 기본적으로 나중에 호출된 함수가 먼저 실행되고 콜스택에서 제거된다.
- **이벤트 큐**(**Event Queue**)는 자바스크립트에서 이벤트나 비동기 로직처럼 콜스택에서 순서대로 처리되는 것들이 아닌 이벤트 루프가 콜스택에 등록시켜 처리되야 하는 일들이 기다리는 곳이다.
- 비동기 로직들은 콜스택이 모두비어질 때까지 이곳에서 기다린다.
- **이벤트 루프**(**Event Loop**)는 계속해서 콜스택과 이벤트큐를 점검하여 콜스택에 등록시킬 태스크들을 점검하고 등록하여 실행하는 역할을 수행한다.
- **Web API**
- `setTimeout`이나 `xmlhttprequest`같이 비동기적으로 실행되는 JavaScript 모듈들은 사실 NodeJS의 V8엔진에 속하지 않는다.
- 이들을 `Web API`라고 하며 이들이 처음 실행될때 콜스택에서 Web APIs로 콜백을 보내고 콜스택에서 바로 사라지는 것이다.
- `Web API` 중 잘 알려진 것으로 `Event, Ajax ,Timer` 등이 있다.
- `Event`는 우리가 잘 아는 `addEventListner`로 event 명과 함께 등록한 콜백을 event가 발생할때마다 이벤트큐에 등록해 준다.
- `Ajax`는 위에서 언급한 `xmlhttprequest`로서 자바스크립트 로직중 통신이 필요한 곳에서 `xmlhttprequest`를 실행시키면 `Ajax`가 통신을 보내고 응답이 오거나 응답이 너무 늦어지면 이에 해당하는 callback을 이벤트큐에 등록시켜 줍니다.
- `Timer API` 는 비동기에 대한 공부를 할때 가장 많이 사용하는 `setTimeout` 혹은 `setInterval` 등으로 특정 시간이 지나고 난 후 혹은 시간 마다 callback을 이벤트큐에 등록시키는 API 입니다.
> 위에서 설명한 것 처럼 Web API가 이벤트큐에 등록한 callback들은 이벤트루프가 콜스택을 점검하고 등록시키는 행위로 처리됩니다.
#### 이상아
> Axios에서 then으로, 받은 promise를 열어줘야 하는 이유
* **만약 then을 쓰지 않는다면...**
```javascript
const doAxios = _ => {
const a = axios.get('...')
console.log(a)
}
doAxios()
```
* 이런 코드가 있다고 가정해보자
* 이 때, call stack, event queue, event loop 에 어떤 변화가 일어나는지 보자
1. doAxios() 가 call stack에 들어간다.
2. `const a = axios.get('')` 이 call stack에 들어간다.
* 그런데, axios는 webAPI에서 처리하므로, webAPI로 넘겨준다
* 따라서, call stack에서 해야 할 일(webAPI 으로 넘기는)을 했으니, call stack에서 axios `const a = axios.get('')` 는 없어지게 된다.
3. console.log(a) 가 call stack에 들어간다.
* 하지만 a가 선언된 상태가 아니기 때문에 `Promise { <pending> }`가 뜰 것이다
* console.log(a) 는 처리가 끝났으니 call stack에서 빠진다
4. doAxios() 함수에선 더 이상 할 일이 없으니, doAxios() 함수도 call stack 에서 빠진다
5. webAPI가 `const a=axios.get('')` 를 마침 다 수행하여, event queue에 넣어준다
* event loop가 call stack이 비어있다고 판단했기 때문에, `const a=axios.get('')`를 call stack에 넣어준다
* 하지만 받아온 것을 쓸 수 있는 것은 아무것도 없으므로 그대로 끝나게 된다.
* **then을 써준다면?**
```javascript
const doAxios = _ => {
const a = axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
console.log(a)
}
doAxios()
```
2. `const a = axios...` 이 call stack에 들어간다
* axios는 webAPI에서 처리하므로 그쪽을 넘긴다
* webAPI에서 처리한 후, 그 결과를 event queue에 넘겨준다
* event queue에서 call back을 열어서 받은 값을 알게 된다
3. 하지만 이미 console.log(a)는 call stack에 들어갔고, 받은 값은 Promise(일단 뭔가는했는데, 결과는 있다 알려줄게) 뿐이기때문에, promise pending이 출력되게 된다.
3. axios처리를 한 callback 함수가 event loop를 타고 call stack으로 들어가게 된다.
4. 출력이 된다.