Call Stack
자바스크립트는 싱글 스레드(single-threaded) 프로그래밍 언어이기 때문에, 콜 스택이 하나이다. 따라서 한 번에 하나의 일만 할 수 있다.
콜 스택은 함수의 호출들을 기록하는 자료구조이다. 기본적으로 우리가 프로그램 안에서 위치한 곳이다.
만약 어떤 함수를 실행시킨다면, 스택 위에 무언가를 올리는(push) 행위를 하는 것이다. 그리고 함수로부터 반환을 받을 때, 스택의 맨 위를 가져오는(pop) 행위를 하는 것이다.
위 코드가 실행되면 호출 스택은 아래와 같이 기록되게 된다.
호출 스택(call stack) | 콘솔(console) |
console.log(d) d(); console.log(c) c(); console.log(b) b(); console.log(a) a(); |
'd' 'c' 'b' 'a' |
[표 해설]
(함수 d 실행 👉🏻 콘솔 로그 d 실행 👉🏻 콘솔로그 d 호출 스택에서 제거 👉🏻 더 이상 실행할 게 없는 함수 d 제거 👉🏻 호출 스택 내부가 아무것도 없는 상태에서 함수 a 실행 👉🏻 함수 a안에 함수 b 실행 👉🏻 함수 b안에 함수 c 실행 👉🏻 콘솔 로그 c 실행 👉🏻 콘솔로그 c 호출 스택에서 제거 👉🏻 함수 c 제거 👉🏻 콘솔로그 b 실행 👉🏻 콘솔로그 b 호출 스택에서 제거 👉🏻 함수 b 제거 👉🏻 콘솔로그 a 실행 👉🏻 콘솔로그 a 호출 스택에서 제거 👉🏻 함수 a 제거)
함수 실행 코드 순서에 따라 콜 스택에 후입선출식으로 올리고(push) 반환을 받을 때, 즉 콘솔에 출력이 되면 빼게(pop) 된다.
Point 함수를 선언한 게 중점이 아닌 함수를 호출한 것이 중요!
함수가 빠져나갈 때마다 스택이 위에서부터 빠져나가는 것 즉, 콜 스택의 각각은 스택 프레임(Stack Frame)이라 한다.
그리고 브라우저 콘솔에서 에러 스택들을 표시해 줄 때에도 콜 스택의 현재 상태를 나타내는 것이다. 실패한 함수를 나타낼 때에는 스택처럼 top부터 bottom까지 나타낸다.(아래 예시)
이러한 오류는 예외가 발생했을 때 스택트레이스가 만들어지는 방식이고, 스택 트레이스란 기본적으로 예외가 발생했을 때 콜 스택의 상태이다.
Stack overflow
가끔 함수를 재귀적으로 여러 번 부르다가 무한 루프에 빠지게 된다. 크롬 브라우저는 16000 프레임의 제한된 스택을 가지고 있어서 이 범위를 넘어서게 되면 아래와 같이 Max Stack Error Reached라는 상태가 되고 실행 중이던 것을 날려버리게 된다. 이러한 날려버리는 것을 스택 날림(Blowing the stack)이라 한다.
Heap(힙)
메모리 할당이 이루어지는 곳이다. 즉, 오브젝트(객체)들은 힙 내부에 할당된다. 힙은 거의 구조화되지 않은 영역(unstructured)의 메모리이다. 변수와 객체들의 모든 메모리 할당은 여기서 일어나게 된다.
Web API
Web API는 브라우저에서 제공하는 API로, DOM, Ajax, Timeout 등이 있다. Call Stack에서 실행된 비동기 함수는 Web API를 호출하고, Web API는 콜백함수를 Callback Queue에 밀어 넣는다.
Queue(큐)
큐는 데이터를 집어넣을 수 있는 선형(linear) 자료형이고 FIFO(First In First Out) 먼저 집어넣은 데이터가 먼저 나오는 특징을 가지고 있다. 그리고 데이터를 집어넣은 enqueue, 데이터를 추출하는 dequeue 등의 작업이 가능하다.
자바스크립트 런타임은 이러한 메시지 큐를 갖고 있다. 메시지 큐는 실행될 콜백 함수나 실행될 메시지들에 대한 리스트라고 볼 수 있다.
스택이 충분한 공간(capacity)을 갖고 있을 때, 메시지는 큐 밖으로 나오게 되고 메시지가 가지고 있던 함수 목록들이 실행된다. 이렇게 초기 스택 프레임이 만들어진다. 스택이 빌 때에는 메시지 수행도 끝나게 된다. 이벤트들에 대한 콜백 함수가 제공되었다 가정했을 때, 이 메시지들은 외부 비동기 이벤트들에 대한 응답으로 큐에 쌓이게 된다.(외부 비동기 이벤트들이란, 클릭이벤트, HTTP 요청 등을 말한다.) 하지만 사용자가 버튼을 눌렀는데 아무런 콜백 함수도 등록되어 있지 않다면 어떠한 메시지도 큐에 들어가지 않게 된다.
콘솔 a가 setTimeout에 있다 생각하고 예를 들어보면, 일단 스택에 다 들어가게 된다. 자바스크립트는 이것을 보고 타임아웃 부분을 Web API로 가져간다.(Web API는 브라우저가 관리) 그리고 나선 콘솔 b를 실행시키고 스택이 끝나게 된다.
setTimeout에서 설정한 시간이 1초라 가정한다면, Web API는 1초를 기다리고 콘솔 a는 메시지 Queue로 가게 된다.
만약 스택에 아무것도 없다면(규칙) 자바스크립트는 queue를 보고 (콘솔 a구나) 스택에 가게 된다.
fetch도 위와 같이 작동한다.
스택에 올라간 후 Web API로 이동할 것이고,
Web API에서는 fetch에 정해놓은 웹사이트를 부를 것이고, 돌아왔을 때 함수는 Queue로 이동하게 된다.
그리고 자바스크립트가 준비되었을 때, queue에서 불러서 함수를 다시 실행하게 된다.
'Javascript' 카테고리의 다른 글
JavaScript - 값 타입(Value Type)과 참조 타입(Reference Type) (0) | 2020.09.07 |
---|---|
JavaScript - Primitive Type (0) | 2020.09.06 |
JavaScript - JSON (0) | 2020.09.02 |
JavaScript - script async와 defer (0) | 2020.08.24 |
JavaScript - object(3) (0) | 2020.07.05 |
댓글