Javascript 실행과 호출 스택

진실·2022년 11월 13일

Javascript Engine

  • javascript가 돌아갈 수 있게 해주는 인터프리터
  • C에도 다양한 컴파일러가 있듯이, JS에도 js engine이 다양하다.
  • 대표적으로는 chrome에서 돌아가는 Google의 V8이 있다.

JS Engine의 구성 요소

Memory Heap

  • OS에서 배울 때처럼 변수, 객체 등이 저장되는 메모리 공간

Call Stack

  • 호출된 함수가 쌓이는 공간

Run Time

  • setTimeout과 같은 함수는 JS Engine이 기본적으로 제공하는 것이 아니라 브라우저에서 제공하는 web API이다.
  • 이런 web API 의 호출을 제어하기 위한 call back queueevent queue가 있다.

Call Stack

  • 함수가 실행될 때 쌓이고, 종료될 때 pop되는 스택

Event Loop

  • JS는 single thread 언어이기 때문에 call stack도 한 개 갖고 있다.
  • 이때 어떤 함수의 실행시간이 굉장히 길면 계속 다음으로 넘어가지 못하게 된다.
  • 따라서, 비동기 콜백을 사용해서 함수를 바로 실행하지 않고, 특정 시점이 됐을 때 실행하도록 한다.
  • 비동기 콜백은 실행되지 않기 때문에 call stack에 올라가지 않고 Event Queue에 들어가서 대기하게 된다.
  • 개념을 정리하자면 JS Runtime 안에 Event Queue가 있다.

Event Queue의 비동기 콜백 처리 과정

  1. DOM Event (click 등), HTTP Request, setTimeout 등의 web API는 비동기 콜백을 갖고 있다.

    ex) addEventListenerclick messagecallback을 인자로 전달한다.

    button.addEventListener('click', event => {
      button.innerHTML = `클릭 수: ${event.detail}`;
    });
  2. Runtime이 Web API를 만나면 비동기 콜백 함수를 Event Queue에 넣는다.

  3. Runtime은 Call Stack이 빌 때를 모니터하고, 빌 때 Event Queue에서 콜백을 가져와서 실행시킨다.

정리

  1. JS를 실행시켜 주는 것을 JS Engine이라고 한다.
  2. 변수와 객체는 메모리 힙에, 함수는 콜 스택에 쌓인다.
  3. DOM, http request, setTimeout과 같은 함수는 JS Engine이 제공하지 않고, 브라우저가 제공하는 C++로 된 비동기 콜백을 갖고 있는 함수이다.
  4. 기본적으로 Runtime에는 콜 스택에 쌓인 함수를 실행시킨다.
  5. 그러다가 Web API 함수를 만나면 콜백을 Callback queue (Event queue)에 집어 넣는다.
  6. Event Loop는 Call Stack이 빌 때를 기다리고 비면 Callback queue에서 콜백 함수를 꺼내서 실행시킨다.

Javascript 삽입 위치

  • 브라우저는 렌더링을 하다가 js를 만나면 js를 해석하고 실행할 때까지 렌더링을 멈춘다.
  • js는 html 하단에 배치하라는 것도 이런 이유
    • body 아래에 위치하게 되면 렌더링 후 실행되기 때문에 DOM을 조작할 수 있게 된다.

  1. HTML을 parsing하다가 <script src=”…” /> 이런 걸 만났다고 생각해보자.
  2. browser는 parsing을 멈춘다.
  3. src에서 JS를 fetch 해 온다
  4. 그럼 fetch된 script는 언제 실행될 것인가?
  5. 기본적으로는 가져오자 마자 script를 실행한다.
  6. 그런데 script가 언제 실행될 지를 조절하고 싶다 → async, defer

async

  1. script tag에 async가 들어가면 script를 fetch하는 동안에도 parsing이 계속 일어난다.
  2. 그리고 script를 가져오면 그제서야 parsing을 멈추고 script를 실행한다.
  3. DOM에 직접 접근하지 않거나, 다른 스크립트에 의존적이지 않은 스크립트들을 독립적으로 실행해야 할 때 효과적

defer

  1. script tag에 defer가 들어가면, html을 parsing하면서 script를 가져오고,
  2. DOM이 다 생성되고 나서 script를 실행할 수 있다.
  3. 따라서 head tag에 script를 넣어도 defer 속성을 넣으면, body 하단에 위치한 것과 같은 효과 !!!!
  4. 모든 DOM element에 접근할 수 있고 script 의존성 문제도 해결
  5. DOM 생성과 fetch를 동시에 한다 해도, fetch가 오래 걸릴 수 있고, execution은 나중으로 미루기 때문에 js가 로드되기 전에 DOM element를 조작하는 문제는 여전히 해결할 수 없다.
profile
반갑습니다.

0개의 댓글