본문 바로가기

JavaScript/Vanila

자바스크립트의 실행 순서 (호출 스택과 이벤트 루프)

반응형

자바스크립트

자바스크립트는 브라우저위에서 동작하기위해 탄생한 스크립트언어이다.

-> Node.js가 크롬 엔진 V8를 내장함으로써 더이상 브라우저에 종속하지 않은 언어로 사용할 수 있도록 함

 

스크립트 언어

: 특정 작업을 자동화하거나 특정 애플리케이션에서 사용할 목적으로 사용되는 언어

 

스크립트 언어의 가장 큰 특징은 변수의 데이터 타입을 런타임에 결정한다는 것이다. [동적 타이핑]

 

하지만 이러한 동적 타이핑의 문제를 해결하기 위해 타입 스크립트가 등장.

-> 컴파일 타임에 에러를 찾고, 객체지향언어의 특징을 가짐


자바스크립트의 실행 순서

  • 호출 스택 : 함수 호출을 기록하는 자료구조로, 함수가 호출되면 해당 함수의 정보가 스택에 쌓이고, 함수가 반환되면 스택에서 제거
  • 테스크큐 : 비동기 작업의 콜백 함수들이 대기하는 공간으로, 비동기 작업이 완료되면 해당 콜백 함수가 테스크 큐에 추가
  • 이벤트 루프 : 호출 스택과 테스크 큐를 모니터링하며, 호출 스택이 비어있을 때 테스크 큐의 작업을 호출 스택으로 이동시켜 실행
  • Anonymous : 가상의 전역 컨텍스트 [파일의 생명주기와 같다]
  • 블로킹-동기 : 함수 스택을 사용하여 코드의 실행 흐름을 관리함. 함수가 호출되면 스택에 쌓이고, 함수가 반환되면 스택에서 제거
  • 논블로킹-비동기 : 테스크 큐를 사용하여 비동기 작업의 완료나 이벤트에 대한 콜백 함수를 관리함.
    *콜백 함수는 테스크 큐에 추가되고, 이벤트 루프를 통해 실행
     
  • 백그라운드 : 비동기 함수를 통해 특정 작업을 수행되는 곳으로 호출스택과 동시에 실행되는 특징을 가진다. [마치, 멀티스레드처럼]
    *백그라운드의 작업보다 호출 스택의 작업이 우선 처리된다. 
    *비동기 함수를 통해 수행되는 특정 작업이 끝나면 테스크 큐로 콜백함수를 보내고, 호출 스택이 비어있으면 콜백함수 호출
  • 호출 스택이 비어있어야만 테스크큐에 있는 작업들을 수행한다.

호출 스택 활용

function sayHello() {
  console.log(this);
}

sayHello(); // 전역 컨텍스트에서 호출되므로 this는 전역 객체를 가리킴

const obj = {
  greet: sayHello
};

obj.greet(); // obj 내의 메서드로 호출되므로 this는 obj를 가리킴

this:

  1. 전역 컨텍스트:
    • 전역 컨텍스트에서 this는 전역 객체(window 또는 global)를 가리킵니다.
  2. 함수 내부:
    • 함수 내에서 this는 함수가 어떻게 호출되었느냐에 따라 결정됩니다.
    • 일반 함수 호출에서는 this가 전역 객체를 가리키지만, 메서드로 호출되면 메서드가 속한 객체를 가리킵니다.

스코프:

  1. 전역 스코프:
    • 전역 변수는 어디서든지 접근 가능한 전역 스코프를 갖습니다.
  2. 함수 스코프:
    • 함수 내에서 선언된 변수는 함수 내부에서만 접근 가능한 함수 스코프를 갖습니다.
let globalVar = 'I am global'; // 전역 스코프

function example() {
  let localVar = 'I am local'; // 함수 스코프
  console.log(globalVar); // 접근 가능
  console.log(localVar); // 접근 가능
}

example();
console.log(globalVar); // 접근 가능
console.log(localVar); // 에러: localVar는 함수 스코프 내부에서만 유효

 

활용

// 예제 1: 스코프를 이용한 호출 스택 활용

function outer() {
  const outerVar = 'I am outer'; // outer 함수 스코프에 있는 변수

  function inner() {
    const innerVar = 'I am inner'; // inner 함수 스코프에 있는 변수
    console.log(outerVar); // outer 함수 스코프의 변수에 접근 가능
    console.log(innerVar); // inner 함수 스코프의 변수에 접근 가능
  }

  inner(); // inner 함수 호출
}

outer(); // outer 함수 호출

// 예제 2: this를 이용한 호출 스택 활용

const myObject = {
  property: 'I am a property',

  myMethod: function () {
    console.log(this.property); // 객체 내에서 this를 사용하여 객체의 프로퍼티에 접근
  }
};

myObject.myMethod(); // myMethod 함수 호출

테스크 큐

 

  1. 콜백 큐 (Callback Queue 또는 Task Queue):
    • 비동기 작업의 콜백 함수들이 대기하는 큐입니다.
    • setTimeout, 이벤트 핸들러, Ajax 요청의 콜백 함수들이 여기에 포함됩니다.
  2. 마이크로태스크 큐 (Microtask Queue 또는 Job Queue):
    • Promise와 관련된 비동기 작업의 콜백 함수들이 대기하는 큐입니다.
    • Promise의 then, catch, finally 등의 콜백 함수들이 여기에 포함됩니다. [백그라운드에서 실행]
    • 마이크로태스크 큐의 우선순위가 더 높아 콜백 큐보다 먼저 실행됩니다.
      [Promise, process.nextTick이 우선순위 높음]

- 큐들은 이벤트 루프의 일부로서, 호출 스택이 비어있을 때 비동기 작업의 콜백 함수들을 호출 스택으로 이동시켜 실행

- 이벤트 루프는 주기적으로 호출 스택과 각 큐들을 확인하며 작업을 처리

- 특히, 마이크로태스크 큐의 작업은 콜백 큐의 작업보다 먼저 처리됩니다.

 


싱글 스레드

  • 스레드 끼리는 부모 프로세스의 자원을 공유하고, 같은 주소의 메모리에 접근이 가능하다.
  • 직접 제어할 수 있는 스레드가 하나 뿐이므로, 노드는 싱글 스레드라고 여겨진다.
    • 논블로킹 방법으로 대기 시간을 최대한 줄이는 방식으로 싱글 스레드의 단점을 해소한다.
  • 스레드가 하나 뿐 이므로, 에러가 발생할 경우 서버 전체가 멈추게 된다.

I/O 작업을 처리할 때 사용하는 멀티 프로세싱 방법

  • cluster 모듈
  • pm2 패키지

노드가 싱글 스레드로 동작하지 않는 경우

  • 스레드 풀
    • 특정 동작을 수행할 때는 멀티 스레드를 사용
    • 암호화, 파일 입출력, 압축
  • 워커 스레드
    • 직접 다수의 스레드를 다룰 수 있는 기능
    • CPU 작업이 많은 경우 사용

 


노드를 서버로 사용하기

 

libuv 라이브러리

  • I/O 처리를 잘하는 노드
  • I/O 작업을 논블로킹으로 처리
  • 스레드 하나가 많은 수의 I/O를 처리

 

단순 데이터 교환으로 많이 사용하는 서버

  • 실시간 채팅
  • 주식 차트
  • JSON 데이터 제공하는 API 서버

CPU를 많이 사용하는 서버

  • 이미지나 비디오 처리
  • 대규모 데이터 처리

정적인 컨텐츠를 제공하는 서버

  • 기본적인 틀안에서 내용물만 달라짐
  • 노드에서는 넌적스, 퍼그, EJS와 같은 템플릿 엔진으로 컨텐츠 제공
반응형