본문 바로가기
안녕하세요 :) FE 개발자 윤지홍입니다.
저는 리액트를 주로 사용해요.
UX/UI디자인에도 관심이 있어요.
Javascript React NextJs NodeJs Flutter HTML CSS PHP
👋
Javascript 동작 원리에 대해 알아보자
jiiii-hong | Javascript | 2022년 08월 17일

Javascript 동작 원리에 대해 알아보자

Javascript 동작 원리에 대해 알아보자

jiiii-hong Javascript 2022년 08월 17일

들어가기

자바스크립트를 몇 년 동안 사용해 오면서 동작원리에 대해 대충은 알고 있었는데 "나중에 제대로 알아보자.. 알아보자.." 하며 미뤄놨었다가 드디어 정리했다 :)

Javascript 동기식 언어다

js는 동기식으로 동작한다. 비동기 처리가 가능하기 때문에 비동기식 언어라고 생각할 수 있지만 javascript는 동기식으로 동작되고 비동기 처리는 아래에서 나오는 WebAPI로 따로 처리한다.

Js는 싱글 스레드

js가 동기적으로 동작하는 이유가 여기에 있다. 싱글 스레드는 한 작업이 종료될 때까지 다음 작업을 실행하지 않고 기다린다.

아래 코드로 살펴보자

alert('hello');
console.log('world');

콘솔을 확인해 보면 알럿트가 닫히기 전까진 'world'가 찍히지 않는 걸 확인할 수 있다.

js에서 오래걸리는 작업을 실행하게 되면 브라우저 화면은 멈춰버린다..

즉 사용자는 아무런 피드백을 받지 못할 것이고 결국 사이트 이탈로 이어질 수 있다..

왜 이런식으로 동작하는지는 Js Engine을 까 보면 알 수 있다.

V8엔진

javascript 엔진은 js코드를 실행하는 프로그램 or 인터프리터다. 그중 대표적인 엔진이 V8엔진(Chrome)이라고 생각하면 된다.

js엔진은 대표적으로 Memory Heap과 Call Stack으로 이뤄져 있다.

 

Memory Heap

메모리 힙이란 메모리 할당이 일어나는 곳으로 변수 선언, 함수 저장 등의 작업이 발생하는 곳이다.

(참조 타입 데이터들이 저장되는 공간이다. 원시 타입 데이터들은 Call Stack에 저장된다.)


Call Stack

콜 스택은 호출 스택이 쌓이는 곳이다. 쉽게 말하면 우리가 작성한 코드를 위에서부터 아래로 읽어가면서 실행할 작업들을 순서대로 쌓아두고 하나씩 순차대로 실행할 수 있게 해주는 곳이다.

(원시 타입 데이터들이 저장되는 공간.)


아래 코드로 확인해보자.

const a = () => {
  console.log("a");
};

const b = () => {
  console.log("b");
};

a();
b();

코드를 보면 a와 b는 메모리 힙에 저장된다. 그리고 a(), b()는 콜 스택에 순서대로 쌓이며 들어온 순서대로 실행되고 빠진다.

여기서 문제는 오래걸리는 작업들이 있는 경우 해당 작업이 완료될 때까지 다른 작업이 중단되는 것이다..!

문제 해결하기 - Web API,  Callback Queue, Event Loop

이러한 문제들을 좀 더 효과적으로 관리하기 위해서 web API, task queue, callback queue, event loop가 필요하다!

 

Web API란?

ajax요청, setTimeout등 브라우저에서 제공하는 API들이다. 브라우저 콘솔에 window를 입력하면 어떤 API들이 있는지 확인할 수 있다.

이 API들을 사용해 무거운 작업들을 비동기로 처리해 다음 작업이 중단되지 않게 처리할 수 있다.

setTimeout, ajax등을 실행한다.


Callback Queue

web API에서 비동기처리가 완료된 후 실행될 콜백 함수들이 여기로 이동되어 대기한다.


Event Loop

이벤트 루프는 현재 실행중인 컨텍스트가 존재하는지 그리고 콜 스택에 대기 중인 작업들이 있는지 반복적으로 확인하고 만약 없다면 callback queue에 있는 작업들을 콜 스택에 순차적으로 이동시키는 작업을 하는 곳이다.


아래 코드가 a -> b -> c 순서가 아닌 b -> c- > a 순서대로 출력되는 이유에 대해 알아보자

setTimeout(() => {
  console.log("a");
}, 0);

const a = () => {
  console.log("b");
};

const b = () => {
  console.log("c");
};

a();
b();

위 코드는 아래와 같은 순서대로 처리된다


1. setTimeout은 비동기 함수이기 때문에 call stack에서 바로 실행되지 않고 callback queue로 이동된다.

2. a와 b의 호출이 순차대로 call stack에 쌓이고 실행된다.

3. 처음에 실행된 setTimeout 실행이 완료되면 해당 콜백 함수는 callback queue로 이동된다.

4. event loop는 call stack이 비어있는지, 현재 실행 중인 컨텍스트가 존재하는지 확인 후 callback queue에 있는 작업들을 call stack으로 이동시킨다.

5. call stack에 있는 console.log("c")가 실행된다.