공부한 내용을 정리합니다.
어쨌든 이벤트 루프는 무엇입니까? | Philip Roberts | JSConf EU
싱글쓰레드 프로그래밍 언어입니다.
싱글 쓰레드 런타임을 가지고 있다는 의미인데, 이것은 하나의 싱글 콜스택만 가지고 있다는 뜻이며, 이는 하나의 프로그램은 동시에 하나의 코드만 실행할 수 있다는 것입니다.
Call Stack은 자료구조로, 실행되는 순서를 기억하고 있습니다. JavaScript에서 함수를 실행하면서 사용됩니다.
JavaScript에서 함수를 실행하려면 스택에 해당하는 함수를 집어넣게 되는데, 함수에서 return이 일어나면 Stack의 가장 위쪽에서 해당함수를 꺼내게 됩니다. 이게 Call Stack이 하는 일입니다. 아래의 예시로 살펴봅니다.
function multifly(a, b){
return a* b;
}
function square(n){
return multifly(n, n);
}
function printSquare(n){
var squared = square(n);
console.log(squared);
}
printSquare(4);
위와 같은 코드를 실행하면,
그리고는 return을 만나 곱한결과를 반환합니다. 무언가를 return할 때 마다 스택 맨 위에 있는 것을 pop합니다. multifly -> square -> printSquare 차례로 pop하게 됩니다. (printSquare의 경우 return 절이 없지만 함수의 마지막 줄에 도달했기 때문에 pop됩니다.)
위에 설명한 내용들이 JavaScript에서 call stack을 이용해서 프로그래밍을 하는 방법입니다.
스택을 날려버렸다는 말을 들어보셨나요?
function foo(){
return foo();
}
위와 같은 코드가 실행되면 callStack에는 foo가 foo를 계속 호출하게 됩니다. 콜 스택에 계속해서 쌓이게 되고 오류가 발생합니다.
Maximum call stack size exceeded!!
위에서 언급했듯이 싱글쓰레드를 사용하는 언어에서는 여러개의 스레드를 사용하지 않는다는 의미입니다. 네트위크 요청을 하고는 끝날때 까지 기다려야하는 방법밖에 없습니다...
동기적인 블로킹이 적용된 브라우저에선 하나의 동작이 실행중이면 다른 일을 할 수 없습니다. 동기적으로 실행되는 네트워크 요청이 콜 스택을 블로킹하기 때문입니다. 벌써부터 속터지는 사람들이 눈에 그려집니다🤬🤯.
이를 해결하기 위해 비동기 콜백을 이용합니다.
console.log('hi');
setTimeout(function cb(){
console.log('what the...')
}, 5000);
console.log('hello');
위 코드가 실행되면 hi
를 출력하고 setTimeout을 실행시킵니다. 콜스택에 setTimeout이 들어가지만 어떤 이유인지 5초를 기다리지 않고 곧바로 사라져 버립니다. 다음 hello
를 출력하고 5초 뒤 what the...
가 출력됩니다. 이는 아래에서 설명하는 Event loop와 관련있습니다.
왜 위와 같은 일이 일어날까요? 여기서 EventLoop와 동시성이 역할을 하게 됩니다.
자바스크립트는 분명히 한가지 일 밖에 할 수 없습니다. 하지만 브라우저가 Web API같은 것들을 제공합니다. (Node역시 Web AP대신 C++ API를 사용할 뿐이지 크게 다르지 않습니다.)
console.log('hi');
setTimeout(function cb(){
console.log('what the...')
}, 5000);
console.log('hello');
위 코드가 실행될 때, hi
가 출력된 후, setTimeout이 실행됩니다. setTimeout은 브라우저에서 제공하는 API입니다. V8엔진에는 없습니다. Javascript가 실행되는 런타임 환경에 존재하는 별도의 API입니다.
브라우저가 타이머를 실행시키고 이건 setTimeout호출 자체는 완료되었다는 의미로 받아들여 stack에게 함수는 제거됩니다.
다음 순서로 hello
를 출력합니다.
여전히 WebAPI에서 실행하고 있는 타이머는 남아있습니다. 5초 뒤 타이머가 종료되면(WepAPI 작동이 완료되면) task queue에 콜백을 넣습니다.
여기서 EventLoop를 사용합니다!
이벤트 루프의 역할은 이렇습니다. stack이 비어있으면 queue의 첫번째 콜백을 스택에 쌓아 효과적으로 실행할 수 있게합니다. 따라서 'hello'의 출력을 마친 stack에 cb가 들어가고 V8엔진으로 'what the...'를 출력시킵니다.