본문 바로가기
javascript

자바스크립트 싱글스레드와 Event Loop

by PudgeKim 2021. 5. 8.

자바스크립트는 싱글 스레드 언어입니다. 그러나 분명히 promise, callback 등을 이용한 비동기 프로그래밍이 가능합니다.
많은 사람들이 이런 부분에 있어서 헷갈려하고 저도 역시 헷갈려서 정리해보았습니다.

 

앞서 말했듯이 자바스크립트는 싱글 스레드 언어 입니다. 하나의 call stack을 갖고 있고 한번에 하나의 코드를 실행할 수 있습니다. 그러나 자바스크립트는 브라우저 위에서 작동합니다. 그리고 브라우저는 멀티스레딩이 가능합니다.
즉, 자바스크립트는 싱글 스레드 언어이지만 런타임시 브라우저 위에서 작동하고 브라우저는 멀티 스레딩이 가능하기 때문에 비동기 프로그래밍이 가능한 것입니다.

 

이를 이해하려면 event loop, stack, task queue의 개념에 대해 이해해야합니다.

stack은 자바스크립트내의 콜스택을 뜻합니다.
task queue는 브라우저가 콜백함수들을 관리하는 큐를 뜻합니다. (자료구조 큐)
event loop은 무한루프를 돌며 stack(js의 콜스택)과 task queue를 관리합니다.

1
2
3
4
5
6
7
console.log('Start');
 
setTimeout(() => {
    console.log('end')
}, 5000);
 
console.log('javascript');
cs

위 코드를 이용해 설명해보겠습니다. 우선 우리가 잘 아는 setTimeout 함수는 브라우저가 제공하는 api입니다.
webapi라고 합니다.

 

1
2
3
4
#Stack#
 
console.log('Hi')
main()
cs

처음에 스택에 main()이 쌓이고 console.log('Start')가 쌓입니다.
그리고 'Hi'가 출력되고 console.log('Start')는 스택에서 사라집니다.

1
2
3
4
#Stack#
 
setTimeout()
main()
cs

그리고 setTimeout 함수가 호출이 되므로 스택에 쌓이는데 브라우저내에서 webapi가 5초를 따로 세고 setTimeout은 스택에서 사라집니다.

1
2
3
4
#Stack#
 
console.log('javascript')
main()
cs

브라우저가 5초는 따로 세는 도중 console.log함수가 스택에 쌓이고 'javascript'를 출력 후에 스택에서 사라집니다. 마지막 코드였으므로 main 함수도 스택에서 사라지고 스택은 비어있게 됩니다.
그리고 5초가 지났습니다. 그럼 webapi는 콜백함수(console.log('end'))를 task queue에 집어넣습니다.

1
2
3
#Stack#                        #Task Queue#
 
console.log('end')    <----    console.log('end')
cs

위에서 event loop은 무한루프를 돌며 스택과 task queue를 관리한다고 했습니다. event loop은 스택이 비게 되면 task queue에 있는 콜백함수를 한번에 하나씩 집어넣게 되고 스택에 올라온 console.log('end') 함수를 실행하고 종료가 됩니다.

** 이렇게 setTimeout의 콜백함수는 task queue에서 스택이 비어질때까지 대기하고 있기때문에 setTimeout함수의 두번째 인자로 주는 시간은 정확히 그 시점에 실행되는 것이 아닙니다. 예를들어 3초를 주었다면 최소 3초후에 실행되는 것이지 정확히 3초후에 실행되는 것은 아닙니다.

 

ajax 요청들은 모두 위 같은 원리로 webapi가 콜백들을 task queue에 밀어넣고, 스택이 비어질때까지 task queue에서 콜백들은 대기하고 있다가 스택이 비면 event loop에 의해서 스택으로 옮겨가고 실행되어집니다.

** 또한 모든 콜백함수가 비동기로 처리되는 것은 아닙니다. async나 promise 등을 이용해야 위에서 설명했듯이 콜백함수가 task queue에 대기하고 event loop에 의해 스택으로 옮겨져서 실행되는 것이지 콜백함수를 썼다고 무조건 비동기로 실행되는 것은 아니라는 것에 주의해야합니다.

 

렌더링도 event loop에 의해 관리되는데 이 렌더링도 스택이 비어져있어야 실행이 됩니다. 그렇기 때문에 사용자가 부드러운 UI를 경험하기 위해서는 스택에서 오래걸리는 작업들(I/O작업 등)이 없어야 하고 이러한 이유로 I/O작업들은 비동기로 처리하는 것입니다.

 

아래 링크를 보시면 더 자세히 설명되어있습니다.
www.youtube.com/watch?v=8aGhZQkoFbQ