230525 자바스크립트 이벤트 루프
자바스크립트 문법반 4주차를 들으면서 동기와 비동기에 대해서 공부를 했는데 3주차에 들었던 콜스택만으로는 비동기 작업에 대해 이해할 수 없었다. 콜스택은 차례대로 들어오고 마지막으로 들어온 것부터 다시 나가는 녀석인데, 비동기라는 말과도 어울리지 않고, 콜스택에 비동기 함수가 들어오면 따로 갈 곳이 없다. 그래서 동기와 비동기를 이해하기 위해서는 콜 스택과 함께 태스크 큐를 알아 볼 필요가 있다.
콜스택에 대한 이해
콜스택
- 자바스크립트에는 후입선출 구조를 가지는 콜 스택(call stack)이라는 저장소가 있다.
- 또한 자바스크립트는 싱글 스레드(single thread)로 동작하므로 한 번에 하나의 동작만 수행할 수 있다.
- 자바스크립트의 일반적인 코드는 동기적으로 동작한다.
- 코드를 실행하다 함수 호출을 만나면 함수 실행 컨텍스트를 콜 스택에 넣는다.
- 그 함수에서 다른 함수를 호출 하면 다시 콜 스택에 쌓는 식이다.
- 그리고 함수 실행이 종료되면 콜 스택에서 마지막 함수(실행 컨텍스트)가 제거된다.
- 일반적으로는 콜 스택이 너무 쌓아 문제가 없다.
- 다만 어떤 함수를 계속 재귀호출을 한다면 콜 스택가 계속 쌓일 것이다.
- 콜 스택은 용량이 무한하지 않으며 정해진 용량이 넘게 쌓이면
Maxmum call stack size exceeded 에러나
Uncaught InternalError: Too much recursion 에러를 발생시킨다.
동기
이러한 동기적 작업의 특성은 작업이 수행인 동안 무조건 기다려야 하는 단점이 있다. 브라우저에서 볼 때는 렌더링이 멈추고 클릭과 같은 이벤트도 수행할 수 없다. 만약 동기 작업이 시간이 오래 걸린다면 화면이 멈춰 있는 시간은 길어져 사용자 입장에서는 답답할 것이다.
비동기
이러한 단점을 보완하는 것이 비동기 작업이다. 비동기 작업이 수행중 일 때에는 다른 이벤트를 수신할 수 있다. 비동기 작업을 수행하는 코드에 의해 콜 스택에 비동기 작업 함수가 들어가면 자바스크립트에서는 webapis로 비동기 함수의 콜백 함수를 보내고 태스크 큐에 쌓이게 된다. 그리고 콜스택이 비어있을 때 이벤트 루프가 콜 스택에 비동기 함수를 올려 실행한다. 결국 비동기 작업 또한 콜 스택에서 수행되지만, 콜 스택이 비어 있을 때만 동작한다.
예시
아래는 func()를 실행하는 코드이다.
func()에서는 updateList()라는 비동기 함수를 실행하고 delay()라는 동기 함수를 실행한다.
delay()는 이중 for문으로 수행 시간이 몇 초 정도 걸리는 함수이다.
과정
- 호출 스택에 func() 추가
- func() 함수 내부에 updateList()를 만나 호출 스택에 추가
- updateList() 내부에서 task(0)를 만나 호출 스택에 추가
- task(0)에서 delay()를 만나 호출 스택에 추가하고 실행
- task(0)가 끝나면 updateList()로 돌아가지 않고 동기 코드인 console.log('delay start')로 넘어간다.
- delay()가 실행되고 끝나면 console.log("function end")가 마지막으로 실행되고 func()가 종료된다.
- 콜스택이 비어있으므로 updateList()가 계속 수행된다.
function task(i) {
console.log(`task [${i}] start`);
delay();
console.log(`task [${i}] end`);
return new Promise((resolve) => setTimeout(resolve, 0));
}
async function updateList() {
console.log("updateList start");
for (let i = 0; i < 10; i++) {
await task(i);
list.children[i].innerHTML = i;
}
console.log("updateList end");
}
function delay() {
for (let i = 0; i < 100000; i++) {
for (let j = 0; j < 100000; j++) {}
}
return;
}
function func() {
updateList();
console.log("delay start");
delay();
console.log("delay end");
console.log("function end");
}
func();
결과
결론적으로 비동기 함수를 먼저 실행하고 바로 다음 줄에서 동기 함수를 실행하면, 비동기 함수가 먼저 실행 중이더라도 동기 함수가 콜 스택으로 들어옴으로써 콜스택이 차게 되고, 콜 스택이 비어있지 않게 되므로 비동기 함수의 동작이 멈추고 동기 함수의 동작을 먼저 수행하게 된다.
- 코드의 순서에 따라 함수를 콜 스택에 쌓인다.
- 비동기 함수는 webapis로 이동하고 태스크 큐에서 기다린다.
- 동기 함수가 모두 실행되어 콜 스택이 비어 있으면 태스크 큐의 비동기 함수가 차례대로 실행된다.
- 비동기 함수가 실행 중일 때 동기 함수로 인해 콜 스택이 차면 비동기 함수의 동작이 멈추고 동기 함수가 먼저 처리된다.
- DOM 변경에 따른 리렌더링 행위는 렌더링 큐에서 따로 관리하며 비동기 함수처럼 콜스택이 비었을 때만 실행되고, 비동기함수의 콜백 보다는 높은 우선순위를 가진다.
한글자료:
'내일배움캠프' 카테고리의 다른 글
230528 내일배움캠프 2주차 WIL (0) | 2023.05.28 |
---|---|
230526 자바스크립트 클래스 (0) | 2023.05.26 |
230524 동기와 비동기 반복문 안에서 html 요소 변경 (0) | 2023.05.24 |
230523 자바스크립트 객체와 배열 메모리 주소와 할당 (0) | 2023.05.23 |
230522 JavaScript 문법반 시작. 1주차 숙제 해결하기 (0) | 2023.05.22 |