본문 바로가기
Programming Language

JS33 - 01.Callstack콜스택 (+ 실행컨텍스트)

by 양찬우 2021. 5. 31.
728x90

execution stack == program stack == control stack == run-time stack == machine stack == call stack

함수 실행에 대한 이해

  • 자바스크립트는 하나의 스레드로 단 1개의 동시성만 다루는 언어
    • 한 번에 1개의 작업만 다룰 수 있다.
    • JS의 Heap Queue Stack -> 크롬의 V8 내부에 구현되어 있다.

1. 콜스택 CallStack

  • 함수의 호출을 기록하는 자료구조
  • 우리가 프로그램 안에서 위치한 곳
  • 함수 실행 시 스택에 push 된다.
  • 함수로부터 반환 받을 때, 스택에서 pop 된다.

2. 힙 Heap

  • 오브젝트(객체)들은 힙 내부에 할당
  • 거의 구조화되지 않은 영역(unstructured)의 메모리
  • 변수와 객체들의 모든 메모리 할당이 여기서 일어남.

3. 큐 Queue

  • 자바스크립트 런타임은 메시지 큐를 갖고 있다.
  • 메세지 큐
    • 실행될 콜백함수나 실행될 메세지들에 대한 리스트
  • 스택이 충분한 공간(capacity)를 갖고 있을 때, 메세지는 큐 밖으로 나오고 메세지가 가지고 있던 함수 목록들이 실행된다. -> 초기 스택 프레임
  • 스택이 다시 빌 때 메세지 수행도 끝난다.
  • 이벤트들에 대한 콜백 함수가 제공되었다면 메세지들은 외부 비동기 이벤트들에 대한 응답으로 큐에 쌓인다.
  • 외부 비동기 이벤트들이란 마우스 클릭, HTTP 요청 등을 말합니다. 하지만 만일 한 사용자가 버튼을 눌렀는데 아무런 콜백함수도 등록되어 있지 않다면 어떠한 메시지도 큐에 들어가지 않을 것입니다.
  • 메시지들은 웹 브라우저에서 언제든 이벤트가 발생했을 때 추가된다.

4. 이벤트 루프 Event Loop

  • 싱글 스레드 언어인 자바스크립트는 스택에 쌓인 함수들에서 어떠한 값을 반환하기 전까지는 즉각적인 반응을 보여줄 수 없다. 즉 즉각적인 반응이 필요할 때 스택이 막혀있다면 아무런 반응을 볼 수가 없다.
  • 따라서 싱글 스레드인 자바스크립트에서 유동적인 UI를 만들기 위해 비동기함수를 사용한다.
  • 비동기 콜백 == 코드의 일정 부분을 실행시키고 나중에 실행될 콜백함수를 스택에 넣는 것 (AJAX)
  • 모든 비동기 콜백들은 코드에서 읽힌 순간 실행되지 않고, 잠시 후에 실행된다.
    • == 동기 함수들과는 다르게 바로 스택 내부로 push되지 않는다.
  • 이벤트 루프가 하는 일?
    • 이벤트 루프는 큐에서 콜백을 실행하고 스택이 비어있을때 스택에 넣는다. 이벤트 루프의 기본 작업은 스택과 작업 큐를 모두 보고 스택이 비어있을때 큐의 첫번째 작업을 스택에 넣는 것이다. 각 메시지 또는 콜백은 다른 메시지가 처리되기 전에 완전히 처리된다.
  • 콜백 함수의 호출은 호출 스택의 초기 프레임으로 사용되며 JavaScript가 단일 스레드이므로 스택의 모든 호출이 반환 될 때까지 추가 메시지 폴링 및 처리가 중단됩니다. 후속 (동기식) 함수 호출은 스택에 새로운 호출 프레임을 추가합니다.
    • 폴링
    • 통신에서, “폴링”은 한 프로그램이나 장치에서 다른 프로그램이나 장치들이 어떤 상태에 있는지를 지속적으로 체크하는 전송제어 방식으로서, 대체로 그들이 아직도 접속되어 있는 지와 데이터 전송을 원하는지 등을 확인한다.

 

실행 컨텍스트

  • 실행 컨텍스트(Execution Context)는 scope, hoisting, this, function, closure 등의 동작원리를 담고 있는 자바스크립트의 핵심원리이다.
  • ECMAScript 스펙에 따르면 실행 컨텍스트를 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이라고 정의한다. 좀 더 쉽게 말하자면 실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경 이라고 말할 수 있겠다. 여기서 말하는 실행 가능한 코드는 아래와 같다.
    • 전역 코드 : 전역 영역에 존재하는 코드
    • Eval 코드 : eval 함수로 실행되는 코드
    • 함수 코드 : 함수 내에 존재하는 코드
    • 일반적으로 실행 가능한 코드는 전역 코드와 함수 내 코드이다.

자바스크립트 엔진은 코드를 실행하기 위하여 실행에 필요한 여러가지 정보를 알고 있어야 한다. 실행에 필요한 여러가지 정보란 아래와 같은 것들이 있다.

  • 변수 : 전역변수, 지역변수, 매개변수, 객체의 프로퍼티
  • 함수 선언
  • 변수의 유효범위(Scope)
  • this

이와 같이 실행에 필요한 정보를 형상화하고 구분하기 위해 자바스크립트 엔진은 실행 컨텍스트를 물리적 객체의 형태로 관리한다.

  1. 컨트롤이 실행 가능한 코드로 이동하면 논리적 스택 구조를 가지는 새로운 실행 컨텍스트 스택이 생성된다. 스택은 LIFO(Last In First Out, 후입 선출)의 구조를 가지는 나열 구조이다.
  2. 전역 코드(Global code)로 컨트롤이 진입하면 전역 실행 컨텍스트가 생성되고 실행 컨텍스트 스택에 쌓인다. 전역 실행 컨텍스트는 애플리케이션이 종료될 때(웹 페이지에서 나가거나 브라우저를 닫을 때)까지 유지된다.
  3. 함수를 호출하면 해당 함수의 실행 컨텍스트가 생성되며 직전에 실행된 코드 블록의 실행 컨텍스트 위에 쌓인다.
  4. 함수 실행이 끝나면 해당 함수의 실행 컨텍스트를 파기하고 직전의 실행 컨텍스트에 컨트롤을 반환한다.

실행 컨텍스트 3가지 객체

  • 실행 컨텍스트는 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이지만 물리적으로는 객체의 형태를 가지며 아래의 3가지 프로퍼티를 소유한다.실행 컨텍스트가 생성되면 자바스크립트 엔진은 실행에 필요한 여러 정보들을 담을 객체를 생성한다. 이를 Variable Object(VO / 변수 객체)라고 한다. Variable Object는 코드가 실행될 때 엔진에 의해 참조되며 코드에서는 접근할 수 없다.
    • 변수
    • 매개변수(parameter)와 인수 정보(arguments)
    • 함수 선언(함수 표현식은 제외)
    Variable Object는 실행 컨텍스트의 프로퍼티이기 때문에 값을 갖는데 이 값은 다른 객체를 가리킨다. 그런데 전역 코드 실행시 생성되는 전역 컨텍스트의 경우와 함수를 실행할 때 생성되는 함수 컨텍스트의 경우, 가리키는 객체가 다르다. 이는 전역 코드와 함수의 내용이 다르기 때문이다. 예를 들어 전역 코드에는 매개변수가 없지만 함수에는 매개변수가 있다.
    • 전역 컨텍스트
    • Variable Object는 유일하며 최상위에 위치하고 모든 전역 변수, 전역 함수 등을 포함하는 전역 객체(Global Object / GO)를 가리킨다. 전역 객체는 전역에 선언된 전역 변수와 전역 함수를 프로퍼티로 소유한다.
    • 함수 컨텍스트
    • Variable Object는 Activation Object(AO / 활성 객체)를 가리키며 매개변수와 인수들의 정보를 배열의 형태로 담고 있는 객체인 arguments object가 추가된다.
    Scope Chain (SC) : Variable object + all parent scopes현재 실행 컨텍스트의 활성 객체(AO)를 선두로 하여 순차적으로 상위 컨텍스트의 활성 객체(AO)를 가리키며 마지막 리스트는 전역 객체(GO)를 가리킨다.
    • 스코프 체인은 식별자 중에서 객체(전역 객체 제외)의 프로퍼티가 아닌 식별자, 즉 변수를 검색하는 메커니즘이다. 식별자 중에서 변수가 아닌 객체의 프로퍼티(물론 메소드도 포함된다)를 검색하는 메커니즘은 프로토타입 체인(Prototype Chain)이다.
    엔진은 스코프 체인을 통해 렉시컬 스코프를 파악한다. 함수가 중첩 상태일 때 하위함수 내에서 상위함수의 스코프와 전역 스코프까지 참조할 수 있는데 이것는 스코프 체인을 검색을 통해 가능하다. 함수가 중첩되어 있으면 중첩될 때마다 부모 함수의 Scope가 자식 함수의 스코프 체인에 포함된다. 함수 실행중에 변수를 만나면 그 변수를 우선 현재 Scope, 즉 Activation Object에서 검색해보고, 만약 검색에 실패하면 스코프 체인에 담겨진 순서대로 그 검색을 이어가게 되는 것이다. 이것이 스코프 체인이라고 불리는 이유이다.this value : context object
    • this 프로퍼티에는 this 값이 할당된다. this에 할당되는 값은 함수 호출 패턴에 의해 결정된다.
  • 예를 들어 함수 내의 코드에서 변수를 참조하면 엔진은 스코프 체인의 첫번째 리스트가 가리키는 AO에 접근하여 변수를 검색한다. 만일 검색에 실패하면 다음 리스트가 가리키는 Activation Object(또는 전역 객체)를 검색한다. 이와 같이 순차적으로 스코프 체인에서 변수를 검색하는데 결국 검색에 실패하면 정의되지 않은 변수에 접근하는 것으로 판단하여 Reference 에러를 발생시킨다. 스코프 체인은 함수의 감추인 프로퍼티인 [[Scope]]로 참조할 수 있다.
  • 스코프 체인(Scope Chain)은 일종의 리스트로서 전역 객체와 중첩된 함수의 스코프의 레퍼런스를 차례로 저장하고 있다. 다시 말해, 스코프 체인은 해당 전역 또는 함수가 참조할 수 있는 변수, 함수 선언 등의 정보를 담고 있는 전역 객체(GO) 또는 활성 객체(AO)의 리스트를 가리킨다.
  • Variable Object가 가리키는 객체는 아래와 같다.
  • Variable Object는 아래의 정보를 담는 객체이다.
  • Variable Object (VO / 변수객체) : vars, function declarations, arguments

실행 컨텍스트의 생성 과정

1. 스코프 체인의 생성과 초기화 2. Variable Instantiation(변수 객체화) 실행 3. this value 결정

  1. 전역 코드에의 진입
    1. 스코프 체인의 생성과 초기화
    2. 변수 객체화 Variable Instantiation 실행
  2. this.value 결정

 

참고

728x90

댓글