실행 컨텍스트, 콜 스택, 싱글 스레드, 스코프 체인

oYJo·2025년 4월 1일

JavaScript

목록 보기
48/52
post-thumbnail

1️⃣ 실행 컨텍스트(Execution Context)

자바스크립트 코드가 실행되는 환경

= 함수 실행에 대한 세부 정보를 담고 있는 내부 데이터 구조

코드가 실행될 때마다 생성된다

  1. https://ko.javascript.info/recursion
  2. https://tc39.es/ecma262/#sec-execution-contexts
  3. http://latentflip.com/loupe/?code=!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D
  4. https://ko.javascript.info/closure

✔️렉시컬 환경
코드가 어디서 실행되며 주변에 어떤 코드가 있는지를 의미

목적

코드가 실행되는 환경 설정, 관리

변수, 함수, 객체 유효 범위 결정

this 바인딩 설정

✔️this 바인딩
this : 객체를 참조하는 키워드

Web에서의 this : window

Node에서의 this : 빈객체(node에서는 dom 관련된 객체가 없기에 다른 런타임)

함수 호출에 따른 this 바인딩

  • 함수 선언식의 this : global 객체
    항상 전역객체에 바인딩 되기에 apply, call, bind 메소드 사용해서 바인딩 해준다
  • this 동적으로 결정

    화살표 함수(arrow function)에서의 this :
  • this 정적으로 결정
  • 렉시컬 this : 언제나 상위 스코프 this 가르킨다

    생성자 함수 사용할 때 this 바인딩 :
  • new연산자를 붙여서 객체 생성하는 함수

    addEventListener 사용시 콜백함수 this :

장점

  • 코드 실행 흐름을 구조적으로 관리할 수 있다
  • 변수와 함수의 유효 범위를 명확하게 구분할 수 있다
  • this를 바인딩하여 객체 지향 프로그래밍을 쉽게 구현할 수 있다

단점

  • 실행 컨텍스트가 많아질수록 메모리 사용량 증가한다
  • 실행 컨텍스트 내부에서 정의된 변수는 가비지 컬렉션이 작동하지 않으면 계속 남아있다
  • 클로저를 사용할 경우 예상치 못한 컨텍스트 유지로 메모리 문제가 발생할 수 있다

실행 컨텍스트 종류

  1. 전역 실행 컨텍스트(Global Execution Context)
    • 자바스크립트 코드가 실행될 때 가장 먼저 생성되는 컨텍스트 = 코드 전체 정보를 가진다
    • window(브라우저) 또는 global(Node.js)이 전역 실행 컨텍스트의 this가 된다
  2. 함수 실행 컨텍스트(Function Execution Context)
    • 함수가 호출될 때마다 생성된다
    • 각 함수는 자신만의 실행 컨텍스트를 가진다
  3. Eval 실행 컨텍스트(Eval Execution Context)
    • eval() 함수가 실행될 때 생성됩니다.
    • 엄청나게 위험하기에, 사용하지 않는다 (보안 및 성능 문제)

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/eval
→ eval() 말고 function 사용 권장

// bad
function looseJsonParse(obj) {
  return eval(obj);
}
console.log(looseJsonParse("{a:(4-1), b:function(){}, c:new Date()}"));
        ```
        
```jsx
// good
function looseJsonParse(obj) {
  return Function('"use strict";return (' + obj + ")")();
}
console.log(looseJsonParse("{a:(4-1), b:function(){}, c:new Date()}"));

✔️eval()
인자로 받은 코드를 caller 권한으로 수행하는 위험한 함수

  • 악의적인 코드 수행 결과 초래 가능
  • JS인터프리터를 사용하기에 느리다

실행 컨텍스트 구성 요소

  1. 변수 객체(Variable Object, VO)
    • 실행 컨텍스트 내에서 선언된 변수, 함수, 매개변수를 저장하는 객체이다
    • 함수 실행 컨텍스트에서는 활성 객체(Activation Object, AO)라고 부르기도 한다
  2. 스코프 체인(Scope Chain)
    • 실행 컨텍스트 내에서 변수나 함수를 찾을 때 참조하는 체인 구조
  3. this 바인딩
    • 실행 컨텍스트에서 this가 가리키는 객체를 정의한다
    • 전역 컨텍스트에서는 window , global

✔️메모리 구조(힙, 스택, 큐)

: 트리 기반 자료구조, 최대값 & 최소값 찾기 위해 설계된 구조
전역적으로 엑세스 가능

스택 : 후입선출, 책더미와 같은 모양
빠른 액세스 가능
ex) 브라우저 뒤로가기

: 선입선출, 대기줄과 같은 모양
ex) 작업 처리 대기열


2️⃣ 콜 스택(Call Stack)

현재 실행중인 서브루틴에 대한 정보들을 담아두는 스택 구조 메모리영역

실행 컨텍스트를 관리하는 자료구조(Stack)

  • 후입선출(LIFO, Last In First Out) 방식으로 작동
  • 함수 실행 시 새로운 실행 컨텍스트가 스택에 쌓이고, 실행이 끝나면 제거된다

목적

  • 실행 중인 코드의 실행 컨텍스트를 추적한다
  • 함수 호출 및 종료를 관리한다

장점

  • 후입선출(LIFO) 방식으로 함수 실행 순서가 명확하다
  • 비동기 프로그래밍(ex. setTimeout, Promise)과 결합하여 효과적으로 실행 흐름을 관리할 수 있다

✔️동기 vs 비동기

동기 : 요청, 결과가 동시에 일어난다
순서에 맞춰 진행, 동시 처리 불가능
→ 직관적 간단 설계 가능


비동기 : 동시에 일어나지 않는다
처리 시간이 긴 작업으로 인한 thread block 없이 처리할 방법이 필요하다 = 자바스크립트는 긴 작업을 메인 스레드에서 처리하지 않는다
= 멀티 스레드에서 작업(백그라운드에서 처리되는 작업)

동시 처리 가능, 하지만 속도 저하
→ 복잡하지만 자원을 효율적으로 사용할 수 있다


콜백 함수 사용 : 비동기 작업이 완료되었을 때 메인스레드에서 실행할 함수

  • ex) AJAX
    브라우저 내에서 비동기 기능을 제공하는 기법
    동적으로 페이지 변화 시켜준다
    웹 페이지 전체를 로딩하지 않고 웹 페이지 일부분만 갱신해준다(가벼워진다)
    좋아요, 추천수 등

  • ex) 사용자가 버튼을 눌렀는데 서버에서 응답이 없다
    동기 : 데이터 로드 될 때까지 아무 동작을 안 한다
    비동기 : 데이터 로드 될 때까지 로딩 화면 등을 통해 유저친화 효과를 줄 수 있다

단점

  • 너무 깊은 재귀 호출(자신을 다시 호출)이나 많은 함수 실행이 발생하면 스택 오버플로우(Stack Overflow) 오류 발생할 수 있다 → while 반복문으로 사용한다
    function infinite() {
        infinite();
    }
    infinite();  // Maximum call stack size exceeded
    
  • 자바스크립트의 싱글 스레드 특성상, 스택이 길어지면 응답성이 저하될 수 있다

예제

function first() {
  second();
  console.log("첫 번째 함수 실행");
}

function second() {
  third();
  console.log("두 번째 함수 실행");
}

function third() {
  console.log("세 번째 함수 실행");
}

first();

// 세 번째 함수 실행
// 두 번째 함수 실행
// 첫 번째 함수 실행
  1. first() 실행 → first 컨텍스트가 스택에 추가
  2. second() 실행 → second 컨텍스트가 스택에 추가
  3. third() 실행 → third 컨텍스트가 스택에 추가
  4. third() 종료 → 스택에서 제거
  5. second() 종료 → 스택에서 제거
  6. first() 종료 → 스택에서 제거

✔️스레드(Thread)
실제 작업하는 주체

메인 스레드 : 브라우저 사용자 이벤트 처리, 디스플레이 전송 페인팅, 대부분 코드 실행하는 데 사용

싱글 스레드

  • 문맥 교환 작업을 요구하지 않는다
  • 자원 접근에 대한 동기화를 신경쓰지 않아도 된다
  • 프로그래밍 난이도가 쉽고 자원 소모 적다
  • 블로킹 : 연산량이 많은 작업을 수행하면 다 끝날 때까지 아무 동작을 못한다

    멀티 스레드
  • 블로킹 현상 극복 : 새로운 스레드 생성으로
    스레드 1개로는 느리기에 멀티 스레드가 있으면 전반적인 성능, 브라우저 전체 성능 보존할 수 있다
  • 프로그래밍 난이도가 높다
  • context switching으로 시간이 많이 소요된다

❗️JS는 싱글 스레드인데 callback 함수, 비동기 어떻게?
A. 멀티스레드인 척 한다(브라우저, Node 환경에서 처리)


Call Stack : 일단 제일 먼저 여기서 처리한다
기본적인 자바스크립트 싱글 스레드 작업 처리

Web APIs : Call Stack에서 처리 못하는 작업은 Web APIs로 넘어간다
자바스크립트 엔진이 아닌 브라우저에서 제공하는 runtime 환경
Dom Event, AJAX, setTimeout 처리

Task Queue(Callback queue는 Task queue 한 종류) : 비동기 처리된 callback 함수가 대기하는 queue

(매크로)태스크 큐 : 콜백함수 이벤트, 타이머, ajax 요청, dom이벤트 핸들러
실제 자료구조는 set으로 구현되어 있다
queue가 아니다

마이크로태스크 큐 : promise의 then(), catch() 메소드, queueMicrotask() 함수
태스트 큐보다 우선 호출된다

Event Loop : 자바스크립트 내 루프
Call Stack, Task Queue 지속적으로 모니터링
처리해야 할 테스트가 있으면 순차적으로 처리
처리해야 할 테스트가 없으면 잠든다
= 대기 중인 오래된 작업을 Call Stack으로 push
스크립트, 핸들러, 이벤트가 활성화 될 때만 돌아간다
https://developer.mozilla.org/ko/docs/Glossary/Thread

✔️큐(queue)
선입선출의 자료구조
대기열, 순서 리스트


2️⃣ 스코프 체인(Scope Chain)

변수를 참조할 때 스코프 계층 구조를 따라 올라가는 매커니즘

= 실행 컨텍스트가 변수나 함수를 찾을 때 참조하는 영역의 연결 리스트

각 실행 컨텍스트는 자신의 변수 객체(VO)와 부모 실행 컨텍스트의 VO를 참조한다

✔️스코프 : 변수가 접근할 수 있는 범위

목적

  • 변수와 함수의 유효 범위를 찾기 위해 사용한다
  • 내부에서 선언되지 않은 변수를 찾기 위해 상위 스코프를 탐색한다

장점

  • 코드의 가독성과 유지보수성 증가한다 (각 함수가 필요한 변수만 접근)
  • 캡슐화(Encapsulation)를 통해 데이터 보호 가능하다
  • 클로저(Closure)를 활용하면 데이터 은닉메모리 최적화 가능하다

단점

  • 스코프 체인이 깊어지면 성능 저하된다 (변수를 찾기 위해 여러 단계를 거쳐야 하니깐)
  • 클로저 사용 시 예상치 못한 메모리 누수될 수 있다
  • var 사용 시 호이스팅(Hoisting)으로 인해 예기치 않은 결과 발생 가능하다
console.log(x); // undefined
var x = 10;

정리

개념목적장점단점
실행 컨텍스트코드 실행 환경 관리, this 바인딩 관리코드 실행 흐름을 구조적으로 관리, 유효 범위 명확실행 컨텍스트가 많아지면 메모리 사용 증가
콜 스택함수 호출 및 실행 컨텍스트 추적함수 실행 순서가 명확, 비동기 코드 처리 가능너무 깊어지면 스택 오버플로우 발생
스코프 체인변수 및 함수의 유효 범위 탐색가독성 증가, 캡슐화 및 데이터 보호스코프 깊어지면 성능 저하, 클로저로 인한 메모리 누수
profile
Hello! My Name is oYJo

0개의 댓글