티스토리 뷰
- 자바스크립트는 싱글 스레드이며, 이것은 Call Stack이 하나라는 이야기이다.
- 자바스크립트는 기본적으로 작업들을 동기 작업을 한다는 의미이다.
- 그런데 어떻게 자바스크립트에서 비동기 작업들이 가능한건지?
- 이벤트 루프, Task queue가 있어서 가능하다
자바스크립트 엔진
Call Stack
- 자바스크립트는 단 하나의 호출 스택(Call Stack)을 사용한다. 처리할 작업들은 차례대로 호출 스택(Call Stack)에 담아서 차례대로 처리한다.
- 하나의 함수가 실행되고, 이 함수의 실행이 끝날 때까지 어떤 task도 수행될 수 없다 (동기 작업).
Task queue (대기실)
- Task queue는 처리할 비동기 관련 작업들을 임시 저장하는 큐이다.
- 비동기 작업에 관련한 Web APIs(setTimeout, Ajax(API호출), 이벤트 등)에 작업은 Call Stack이 아닌 Task queue에 들어온다.
- 이벤트 루프에 의해 Call Stack이 비워질 때마다 Task queue에서 처리해야할 작업들을 순차적으로 Call Stack으로 불러와서 실행하게 해주는 역할을 한다.
- 자바스크립트 엔진에는 단일 스레드이기 때문에 Call Stack이 하나 존재하며, 자바스크립트 엔진 외부(브라우저 환경, Node.js 환경)에 Task queue가 존재한다.
- 자바스크립트에서 비동기 작업이 가능한 이유 (이벤트 루프, Task queue)
- 예시1
- 1. setTimeout함수가 실행되고, 그 안의 콜백 함수가 Task queue에 들어간다
- 2. alert()가 Call Stack에서 실행되고 작업을 마친다.
- 3. 이벤트 루프는 Call Stack이 비워졌는지, Task queue에 처리할 작업이 있는지 확인하고 실행한다
- 4. Call Stack이 비워지고, setTimeout에서 지정한 시간이 지나면 Task queue에 있는 작업이 실행된다
setTimeout(() => alert("World"), 1000); // Hello alert("Hello"); // World
- 예시2
- 1. 1이 call Stack에서 실행된다
- 2. 0초라 할지라도 setTimeout함수이기 때문에 일단 Task queue에 들어간다
- 3. 3이 call Stack에서 실행된다
- 4. call Stack이 비워졌는지 보고, Task queue에 있던 작업이 실행된다
alert(1); // 1
setTimeout(() => alert(2), 0); // 3
alert(3); // 2
Heap
- 메모리 할당해준다
- 변수, 함수, 객체(인스턴스) 등이 담겨져 있다
이벤트 루프(Event loop)
- 이벤트 루프는 Call Stack이 비워질 때마다 Task queue에서 처리해야할 작업들을 실행하는 역할을 해준다.
- Call Stack에서 현재 실행중인 작업이 없는지, Task queue에 작업들이 있는지를 반복적으로 확인하여 실행한다
- Task queue에서 들어온 순서대로 처리한다
이벤트 루프 활용 예시
- 엔진이 동기 작업을 할 때 동안엔 렌더링이 절대 일어나지 않는다. 이것은 작업을 처리하는 데 걸리는 시간이 짧으면 전혀 문제가 되지 않지만, 작업 처리에 긴 시간이 걸리면, 브라우저는 작업을 처리하는 동안에는 발생한 사용자 이벤트 등의 다른 새로운 작업들을 처리하지 못해서 ‘지연’ 또는 ‘멈춤’ 현상이 발생한다
- (예시) 작업을 처리하는데 걸리는 시간이 길 때
- alert창이 뜰 때까지, 다른 작업(마우스 오른쪽 버튼 클릭) 등을 할 수가 없다
let i = 0; function count() { for (let j = 0; j < 1e9; j++) { i++; } alert("완료"); } count();
- (해결법) 작업 쪼개고, 비동기 처리 setTimeout을 이용하기
- alert창이 뜨기 전에도, 다른 작업(마우스 오른쪽 버튼 클릭) 등을 할 수 있다
let i = 0; function count() { do { i++; } while (i % 1e6 != 0); // 작업 쪼개기 if (i == 1e9) { alert("완료"); } else { setTimeout(count,0); // 다시 함수 호출 } } count();
- 1. Call Stack에 있는 부분 작업을 마치고,
- 2. setTimeout함수를 실행하고, 콜백 함수를 Task queue에 넣는다
- 3. 이벤트 루프는 Call Stack이 비워졌는지, Task queue에 처리할 작업이 있는지 확인하고 실행한다
- 4. Call Stack이 비워지고, setTimeout에서 지정한 시간이 지나면 Task queue에 있는 작업이 실행된다
- 5. 나머지 부분 작업을 마친다
- 6. 이런 식으로 무거운 작업을 쪼개고, 중간 중간에 이벤트 루프가 돌아갈 수 있게 비동기 처리를 해서 Task queue의 작업이 들어가도록 ‘환기’를 해주면, 다른 동작(사용자 이벤트 등)에 반응하면서 무거운 테스크 처리가 가능해진다
Microtask queue
- 사실 Call Stack, Task queue외에도 Microtask queue가 존재한다.
- 비동기 관련 Web APIs(setTimeout, Ajax(API호출), 이벤트 등) 작업 중에서 모두 Task queue로 들어가는 것이 아닌 Promise의 then()일 경우 Microtask queue로 들어가게 된다.
실행되는 순서는 Call Stack → Microtask queue → Task queue 이다.
이벤트 루프는 Call Stack → Call Stack 비워져있는 것 확인 후 → Microtask queue확인 후 Call Stack으로 넣어줘서 실행 → Call Stack과 Microtask queue이 비워져있는 것 확인 후 → Task queue확인 후 Call Stack으로 넣어줘서 실행되게 해준다.
그래서 코드로 구현을 하면 다음과 같은 순서로 실행되는 것을 확인할 수 있다.
console.log("script start");
setTimeout(function() {
console.log("setTimeout");
}, 0);
Promise.resolve().then(function() {
console.log("promise1");
}).then(function() {
console.log("promise2");
});
console.log("script end");
/* 순서
script start
script end
promise1
promise2
setTimeout
*/
'프론트엔드' 카테고리의 다른 글
웹팩의 빠른 로딩 속도 비교하기 (0) | 2022.08.11 |
---|---|
useRef와 useState의 변화에 따른 렌더링 차이 (0) | 2022.08.07 |
PR에서 테스팅 후 성공시에만 자동 Merge하기 (0) | 2022.08.03 |
useState 비동기 작동, 불변 메서드 문제 해결 과정 (0) | 2022.08.01 |
www.naver.com을 입력했을 때 일어나는 일 (0) | 2022.06.15 |
댓글
- Total
- Today
- Yesterday