pgg-dev
[JavaScript] 이벤트 루프(Event Loop) 본문
자바스크립트는 싱글 스레드 프로그래밍 언어이다.
하나의 프로그램은 동시에 하나의 코드만 실행할 수 있다는 말이다.
one thread == one call stack == one thing at a time
호출 스택(call stack)은 프로그램 상에서 실행되는 순서를 기록하는 데이터 구조이다.
함수를 실행하면 스택에 함수를 추가(push) 하고, 리턴이 일어나면 스택의 가장 위쪽부터 제거(pop)한다.
호출 스택 작동 원리
엔진이 코드를 실행하기 전에는 호출스택이 비워져 있다.
코드를 실행하면 코드 자체인 main 함수를 스택에 집어넣는다.
함수들을 각각 정의하고, 마지막에 printSquare를 만난다.
함수를 호출하기 때문에 스택에 추가하고, 다시 square가 추가된다.
square는 multuply 함수를 호출하기 때문에 스택에 추가된다.
리턴절을 만나서 결괏값 반환하고, 무엇인가 리턴할 때마다 스택 위에 있는 것을 꺼낸다
mutiply에서 square로 리턴되고 printSquare까지 돌아오고 console.log를 실행한다.
스택 오버플로우
스택오버플로우는 스택의 사이즈를 초과했을 때 발생하는 오류이다.
main 함수가 foo를 호출하고, foo 함수는 또다시 자기 자신 foo 를 호출하는 구조이다.
무한 호출되는 재귀 함수는 위와 같은 오류를 만든다.
블로킹(blocking)
블로킹은 오래 걸리는 작업이 스택에 남아 있는 것을 가리킨다.
오래 걸리는 작업을 동기적으로만 실행할 수 있다고 가정한다면, 그다음 작업들은 무한정 대기해야 한다.
후속 작업을 실행하기 위해서 이전 작업이 완료될 때까지 기다려야 하는 상황이 발생하는 것이다.
이 문제는 사용자들에게 상당한 불편함을 준다.
작업이 실행되는 동안 브라우저가 다른 작업을 할 수가 없기 때문에 먹통이 된다.
이것의 해결 방안이 Asynchronous Callbacks(비동기 콜백)이다.
자바스크립트가 싱글 스레드 언어임에도 불구하고 우리가 끊김 없이 여러 작업을 동시에 할 수 있는 이유다.
브라우저가 Web API 를 제공하여 비동기 작업을 가능하게 해 주기 때문이다.
비동기 작동 원리
함수를 호출하게 되면 call stack에 차곡차곡 쌓여 순차적으로 실행된다.
이때 만약에 AJAX나 setTimeout 혹은 DOM event 함수와 같은 Web API를 실행하면 자바스크립트 엔진은 call stack에서 Web APIs로 보내고 정해진 시간 혹은 이벤트가 발생한 순간에 순차적으로 callback queue에 적재한다.
callback queue에 줄을 선 함수들은 call stack에 쌓여있던 것들이 모두 제거되어 깨끗해지면 차례대로 스택에 쌓여서 실행되게 된다.
이벤트 루프 역할
위 예제는 setTimeout()을 사용했을 때, 어떤 식으로 동작하는지 그림으로 나타낸 것이다.
먼저 main() 함수가 실행되고, console.log(1)이 스택에 쌓인다.
console.log(1)이 실행되어 콘솔 창에 1이 출력되고 setTimeout의 콜백 함수인 cb가 스택에 쌓이는데,
setTimeout은 브라우저에 의해 제공된 API로 자바스크립트 엔진에서 처리하지 않고 바로 web APIs로 넘긴다.
그러면 브라우저가 타이머를 실행시키고, 이것은 마치 setTimeout 함수가 완료된 것처럼 스택에서 지워져 있다.
(하지만 Web APIs 에 setTimeout 함수가 남아있다.)
그리고 다음 작업을 진행하므로 console.log(3)이 실행되어 콘솔 창에 3이 출력된다.
모든 코드가 실행되었으므로 main() 함수가 스택에서 제거되고,
이 순간에 이벤트 루프가 동작한다.
이벤트 루프의 역할은 콜스택과 테스크 큐를 주시하는 것이다.
이벤트 루프는 스택이 비어있는 것을 확인하고 첫 번째 콜백을 스택에 쌓아 실행할 수 있게 한다.
5초 동안 대기하고 있던 cb 함수가 5초가 지난 시점에 task queue에 들어온다.
stack이 비어있으므로 cb 함수를 stack에 적재하고 console.log(2)를 실행하게 된다.
지금 이 코드는 setTimeout이 5초 후에 실행하는 코드이기 때문에 명백하게 1 - 3 - 2의 순서로 출력된다.
그렇다면 만약에 setTimeout 함수를 0초 후에 실행하도록 코드를 변경하면 어떤 결과가 일어날까?
이 경우에도 결과는 크게 다르지 않다.
그 이유는 task queue에 줄 서 있는 callback 함수들은 stack이 비어있을 때만 stack으로 이동할 수 있기 때문이다.
위 경우 setTimeout으로 설정한 cb 함수는 web APIs로 이동하는 즉시 task queue로 이동하게 되는데,
stack이 비어있지 않기 때문에 대기 상태로 있게 되고 console.log(3)이 출력되고 스택이 클리어 되면 이동하여 console.log(2)가 실행된다.
[참고]
'JavaScript' 카테고리의 다른 글
[JavaScript] 스코프(Scope) (0) | 2020.02.04 |
---|---|
[ECMAScript6 / ES6] Map , Set (0) | 2020.01.22 |
[JavaScript] 호이스팅(Hoisting) (0) | 2020.01.09 |
[ECMAScript6 / ES6] Promise (0) | 2020.01.08 |
[JavaScript] 프로토타입(prototype) (0) | 2020.01.07 |