자바스크립트 이론 부시기

HyunHo Lee·2022년 9월 18일
126

개념

목록 보기
11/14
post-thumbnail

어린 시절에 상상한 개발자

초등학생 시절에는 개발자라고 하면 영어로 된 무언가를 입력해서 원하는 프로그램을 뚝딱뚝딱 만드는 사람이었다. 하지만 개발자로 성장하면서 다양한 분야의 개발이 있어 직군마다 똑같은 영어를 두드리는 것이 아니라 개발 직무에 맞는 언어가 있다는 사실을 알게되었다. 예시로 BackEnd에서는 Java, Kotlin, Python, JavaScript 등을 많이 사용한다. Android는 Java, Kotlin을 사용하고, IOS는 Swift를 사용하며 Web FrontEnd에서는 JavaScript를 사용한다.


그런데 생각해보니 뭔가 조금 이상하다. 다른 직군은 다양한 언어중에 많이 사용하는 언어가 정해져 있어도 다른 언어도 사용하기는 한다. 한국에서 BackEnd 개발자는 Java를 많이 사용하지만, 프로젝트의 목적이나 개발자 취향에 맞게 JavaScript를 이용하기도 한다는 것이다. 하지만 FrontEnd는 압도적으로 JavaScript다.

자바스크립트를 사용하다보면 위의 짤처럼 이해할 수 없는 부분들이 있다. 그럼에도 프론트엔드 개발자들은 JavaScript(TypeScript는 필수..!)를 사용한다는 것이다. 그렇다면 완벽하지 않은 이 언어를 프론트엔드에서는 왜 선택한 것일까? 더불어 자바스크립트는 웹에서 어떤식으로 동작할까? 오늘의 주제는 자바스크립트로 코딩하는 것이 아니다. 자바스크립트에 대해 이야기 하면서 마주치는 개념들에 대해 알아볼 것이다.


자바스크립트의 탄생

1993년에 처음으로 Netscape라는 정적인 웹사이트가 등장했다. 웹사이트라기 보다는 웹문서에 가까워서 동적으로 만들기 위해 브렌든 아이크는 10일만에 Mocha를 만들었다.추후에 Java의 인기가 많다며 이름을 JavaScript로 지어버렸다. 이렇게 JavaScript 등장 이후 DOM 요소의 조작이 가능해졌다.

사실 지금의 자바스크립트는 많은 우여곡절을 경험했다. 갑자기 Microsoft에서 Netscape브라우저를 Reverse Engineering하여 JScript라는 것을 만들어버린 것이다. 그리고 브라우저간 경쟁으로 인해 각종 브라우저들이 자사 브라우저에서만 동작하는 기능들을 추가했다. 당연히 크로스 브라우징 문제가 발생할 수 밖에 없었고, 모든 브라우저에서 똑같이 동작하는 웹 페이지는 개발자의 꿈이 되었다.

이 문제점들을 해결하기 위한 시도로 자바스크립트의 표준화인 ECMAScript가 등장한다. 하지만 IE의 시장 점유율은 독보적이였고, MS사는 ECMAScript를 무시하게 된다. 더 고통받게 된 개발자들이 하나 돌 모여 거대한 커뮤니티가 생겼고, 집단 지성으로 다양한 라이브러리와 브라우저가 등장하게 된다. 자바스크립트는 무시무시한 속도로 발전하게 되어 웹 브라우저에서 동작하는 유일한 프로그래밍 언어가 된다. 현재 상용화되고 있는 브라우저는 모두 자바스크립트를 지원하고 있을 정도로 JS는 중요한 존재가 된 것이다.

더 자세한 역사가 궁금하다면 자바스크립트란? 글을 참고하자.


자바스크립트의 매력..?

자바스크립트의 눈물나는 성공기를 잘 봤다. 이제는 자바스크립트는 어떤 매력을 갖고 있는지 알아볼 시간이다. 사실 한번이라도 사용해보면 바로 알 수 있다. 배우기가 쉽고, npm을 이용하여 다양한 라이브러리들을 설치해서 사용할 수 있어 확장성이 좋다.

심지어는 바닐라 자바스크립트에서 끝나는 것이 아니라 프론트엔드 개발의 생산성을 높여줄 수 있는 React나 Angular 같은 자바스크립트 기반의 SPA도 나오게 된다.

이제 프론트엔드 개발을 하기 위해 새로운 언어가 등장한다기 보다는 자바스크립트의 꾸준한 업데이트와 자바스크립트를 이용한 무언가가 등장하며 발전해나가는 형태가 되었다.


인간미(?) 넘치는 우리의 자바스크립트 ^^

자바스크립트를 이용하여 웹 개발을 하다보면 고려해야할 점과 여러 문제점들이 존재한다.

필수로 들어야 하는 의무 교육을 개발자 친구가 명령어로 스킵하는 것을 목격한 사람이 있을 것이다. 자바스크립트 코드는 쉽게 노출되기 때문에 이렇게 악의적인 목적으로 사용할 수 있다. 더 나아가 데이터를 손상시킬 수 있는 코드도 작성할 수 있으므로 조심해야한다. 그러므로 자바스크립트 코드에 민감한 정보를 다루지 않는 것이 중요하다.


크로스 브라우징

이 외에도 자바스크립트를 이용하여 웹 개발을 할 때 발생하는 문제점들은 많다. 이 중에서 개발자로써 고통받는 부분중 하나가 크로스 브라우징이다. 한 마디로 분명 똑같은 코드를 작성했는데 사파리와 크롬에서 다른 UI를 보여주는 것이다.

브라우저마다 렌더링 엔진과 자바스크립트 엔진이 다르기 때문에 크로스 브라우징 문제가 발생한다. 심지어 같은 브라우저라도 버전마다 지원하는 기능 차이도 심하다. 프론트엔드 개발자는 자신이 설계할 웹이 어떤 브라우저까지 지원할 것인지 고민하는 것이 중요해 보인다. 프론트엔드 개발자가 모니터를 많이 쓰는 이유인가..(변명중)


인터프리터 언어와 컴파일 언어

자바스크립트의 뒷담화(?)는 여기까지 하고 언어 자체의 특징도 알아보자. 자바스크립트는 인터프리터 언어이다. 프로그램을 실행하면 코드를 한 줄씩 읽으며 실행하게 된다. 코드를 기계어로 변환 후 파일을 생성하는 과정이 없어 메모리가 절약된다는 장점이 있다. 하지만 자바스크립트라는 언어로 되어있는 코드를 한줄한줄 해석해서 읽기 때문에 런타임에서 느리다는 단점이 있다.

또한, 에러가 발생하면 그 이후의 코드는 실행되지 않는 특징도 있다. 사실 이 특징은 장점이자 단점이기도 하다. 에러가 하나 발생하면 프로젝트 전체가 동작하지 않을 수 있지만, 에러는 빠르고 신속하게 발견할 수 있다.

그렇다면 컴파일 언어에는 어떤 장점이 있길래 C나 Java가 이 방식을 이용할까? 컴파일 언어는 말 그대로 코드 전체를 기계어로 변환하고 Object Code를 생성한다. 그 후 Object Code를 묶어서 하나의 실행 파일로 만드는 링킹 작업까지 수행한다. 이 과정에서 시간이 소요되고, 많은 메모리를 사용한다. 하지만 이미 기계가 이해하기 쉽게 변환했기 때문에 런타임 상황에서는 신속하기 때문에 전체 실행 시간을 비교해보면 컴파일 언어가 더 빠르다. 마지막으로 인터프리터 언어와는 달리 컴파일러는 오류 메세지를 생성하기 위해서는 전체 코드를 검사한다.


인터프리터에 컴파일 싸먹기

인터프리터 언어의 치명적인 단점은 느리다는 것이다. 나도 프론트엔드 개발자이지만 완벽한 한국인이라 웹 사이트를 이용하면서 로딩창에 2초만 머물러도 닫기 버튼에 마우스를 올린다. 아무리 유용하고 멋진 UI를 가진 웹사이트여도 느리면 안본다는 것이다.

구글의 V8 자바스크립트 엔진은 자바스크립트 런타임의 속도를 증가시키기 위해서 등장하게 된다. 브라우저에만 동작하던 자바스크립트를 브라우저 이외의 환경에서도 동작시킬 수 있는 Node.js도 V8을 이용한다.

tip ) V8 엔진은 C++로 구현되었고, ECMASCRIPT와 WebAssembly 표준에 맞게 구현되었다.

V8은 인터프리터에 컴파일 기능을 추가했다. 전체 코드를 이용하는 컴파일과 한 줄씩 해석하는 인터프리터를 어떻게 합쳤다는걸까? 우리는 먼저 인터프리터 언어와 컴파일 언어에 대한 또 다른 차이점 하나를 이해해야 한다.

인터프리터 언어는 함수가 같은 결과를 반환하더라도 여러 번 호출하면 함수를 여러 번 실행한다. 이에 반해 컴파일 언어는 함수를 호출하면 값을 기억하고, 다시 호출하면 기억한 값을 반환한다. 인터프리터 언어는 이 특징으로 인해 효율도 좋지 못하고, 속도 측면에서도 떨어진다.

자바스크립트 엔진 V8을 사용하더라도 자바스크립트는 인터프리터 언어이기 때문에 코드를 한 줄씩 읽는 것은 동일하다. 하지만 이 과정에서 Profiler는 코드를 지켜보다가 위의 예시와 같은 최적화 할 수 있는 부분을 발견하면 코드를 컴파일러에게 전달해준다는 점이 다르다. 이 방식을 JIT(Just-In-Time) 컴파일러라고 한다.

물론 자바스크립트 엔진에는 V8만 있는것이 아니라 브라우저별로 존재하고 있다. 크롬은 V8, 파이어폭스는 Spider Monkey, 이제는 사라져버린 IE는 Chakra, 사파리는 Webkit이다.

Edge도 Chakra를 사용하고 있지만, 이제 V8을 사용할 예정이라고 한다.


자바스크립트가 웹에서 동작하는 방식

자바스크립트가 실행되는 시점

프론트엔드 개발자라면 브라우저 렌더링의 동작을 알고있을 것이다. 이 과정에서 자바스크립트가 실행되는 시점은 HTML을 parsing하다가 script 태그를 만나는 순간이다. 이 스크립트에 대한 해석과 실행이 완료될 때까지 렌더링을 멈추게 된다. 렌더링이 정상적으로 끝난 후에 실행하고 싶다면 body 하단에 script 태그를 위치시키자.

하지만 어쩔 수 없이 head태그에 추가하는 경우도 있다. cdn을 가져온다던가 제이 쿼리를 사용한다던가.. 그런 경우이다.

만약에 스크립트가 렌더링을 방해하는것을 방지하고 싶다면 async 또는 defer 속성을 이용하자. async 속성은 외부 스크립트에만 사용할 수 있고, 스크립트를 비동기적으로 실행하여 브라우저가 페이지를 파싱하는 동안에도 스크립트가 사용가능해지면 바로 실행한다. defer 속성은 비동기적으로 스크립트를 다운로드 하고, 렌더링이 완료된 후 스크립트를 실행한다.


자바스크립트 엔진 동작

자바스크립트 엔진이 어떤 식으로 동작하는지도 알아보자. 먼저 자바스크립트 엔진에는 하나의 메모리 힙과 콜 스택이 존재한다. 메모리 힙은 참조 타입(배열, 객체, 함수 등)의 메모리 할당에 사용되는 비정형 메모리다. 콜 스택은 원시 타입(number, string 등) 데이터가 저장된다.

const a = 30;
const b = { name: "ayaan" };

30은 원시 타입이므로 변수명인 a, a가 가리킬 주소1, 저장된 값 30이 콜 스택에 저장된다.
객체는 참조 타입이므로 변수명인 b, b가 가리킬 주소2, 메모리 힙에 저장된 객체를 가리킬 주소3이 콜 스택에 저장된다. 메모리 힙에는 주소3과 해당 주소에 맞게 저장된 객체 { name: "ayaan" }가 있는 것이다.

tip ) 나중에 어떤 변수도 가리키고 있지 않은 주소는 가비지 컬렉터가 알아서 수집한다.

그리고 콜 스택은 작성한 코드의 실행에 따라 호출 스택을 쌓는 영역이기도 하다. 실행될 순서를 기억하고 있다가 스택의 가장 위에 있는 것 부터 빼서 실행한다.

함수를 while같은 반복문을 이용하여 무한적으로 호출하게 되면 콜 스택이 초과하여 브라우저는 Maximum call stack size exceeded 에러를 던져준다.

자바스크립트의 또 다른 특징으로는 싱글 스레드이기 때문에 하나의 콜 스택만을 가지게 된다는 것이다. 한 번에 하나의 일(Task)만 처리할 수 있다.

이제 싱글 스레드의 특징을 알아보며 자바스크립트에 대해 조금 더 이해해보자.


싱글 스레드

자바스크립트는 싱글 스레드이므로 한 번에 하나의 일만 처리하는 동기적(Synchronous)인 언어이다. 웹 브라우저는 서버와 통신할 때, 비동기적으로 처리한다. 그런데 만약에 브라우저가 동기적으로 AJAX요청을 보낸다면 어떻게 될까?

응답이 오지 않는 동안에 계속 기다리기만 하는 블로킹(Blocking)이 발생할 것이다. 블로킹이 발생하면, 유저가 마우스 클릭과 같은 어떤 동작을 해도 아무런 반응도 하지 않는다.

그래서 웹 브라우저는 AJAX요청을 비동기로 처리하는 것이다. 이쯤에서 웹 브라우저가 어떤 마법을 부려서 비동기로 처리해지는지 궁금해진다.


Web API

Web API는 브라우저와 함께 제공된다. 콘솔에 window 객체를 출력해본적이 있는가?

여기에 Web API에 관련된 HTTP 요청(AJAX), setTimeout , DOM Event 등이 포함되어 있다. 이 외에도 브라우저에서 제공하는 캐싱이나 데이터 저장소도 있다.

그렇다면 이 Web API를 어디에서 사용할까?


자바스크립트 런타임

Web API는 자바스크립트 런타임에서 이벤트 루프(Event Loop)콜백 큐(Callback Queue)를 이용해서 비동기 요청을 처리할 수 있게 도와준다.

콜백 큐는 태스크 큐 (Task Queue)라고도 불린다.
이벤트 루프와 콜백 큐는 자바스크립트 엔진에 포함되어 있다.

자바스크립트 엔진의 쓰레드와는 다른 쓰레드에서 비동기 요청을 처리한다. 비동기 콜백을 이용하여 싱글 스레드의 한계를 해결해주는 논 블로킹(Non-Blocking)을 수행하는 것이다.

자바스크립트가 비동기 언어라고 오해하는 이유가 바로 비동기적으로 요청을 처리할 수 있도록 조작이 가능하기 때문이었다...

이제 자바스크립트 런타임을 그림과 함께 이해해보자.

  1. 자바스크립트 엔진은 함수를 실행하기 위한 각종 정보들인 전역 실행 컨택스트(Global Execution Context)를 콜 스택에 푸시한다. 그리고 함수의 호출문을 만나면서 실행 컨택스트(Execution Context)도 콜 스택에 푸시한다.
  2. Web API에서 제공하는 요소를 만나면 이것도 일단 콜 스택에 추가하면서 시작된다.
  3. 자바스크립트 엔진은 비동기 작업에 대한 정보와 콜백 함수를 Web API를 통해 브라우저에게 넘기고, 브라우저는 별도의 쓰레드에 위임하게 된다. 그리고 즉시 콜 스택에서 Web API 요소를 Pop한다.
  4. 별도의 쓰레드에서 비동기 작업이 완료되면 콜백 함수를 FIFO(First-In First-Out) 구조의 콜백 큐로 넘긴다.
  5. 이벤트 루프는 콜 스택이 비어있는지에 대한 여부와 콜백 큐에 콜백 함수가 있는지 계속 체크하고 있다. (콜 스택은 전역 실행 컨택스트까지 비워져야 한다.)
  6. 콜 스택에 쌓여있던 작업들이 수행되어 모두 비워지면 콜백 큐는 콜 스택으로 콜백 함수를 넘겨준다.
  7. 이제 콜 스택은 원래 하던대로 위에서부터 꺼낸다.

이 과정으로 인해 비동기 작업이 완료된 이후에 콜백 함수가 실행되는 것이다.

const name = () => {
	console.log("Ayaan")
}

setTimeout(name, 1000);

여기에 1초 뒤에 name이라는 콜백 함수가 있다고 가정하자. 그렇다면 name함수는 무슨일이 있어도 1초뒤에 실행되는 것일까? 우리는 바로 위의 설명에서 힌트를 찾을 수 있다. 콜백 큐에서 콜 스택으로 넘길 때, 콜 스택이 무조건 비워져있어야 한다. Web API에서 비동기 작업이 완료되어 콜백 큐로 넘겼더라도 콜 스택에 작업이 남아있으면 넘겨주지 못한다는 것이다. 그러므로 무조건 1초뒤에 name 함수가 실행되는 것이 아닌 최소 1초뒤에 실행되는 것이다.


Node.js는?

이번에는 웹에서 동작하는 자바스크립트가 아닌 Node.js에서의 동작을 알아보자. 먼저 노드는 싱글 쓰레드일까? 엄밀하게 말하면 싱글 스레드는 아니지만 자바스크립트를 실행하는 스레드는 하나여서 싱글 스레드라고 한다. (어쨋든 Node.js는 싱글 스레드라고 많이 부른다.)

우리는 위에서 V8을 사용하는 크롬 브라우저가 동시성을 위해 어떤 동작들을 하는지 알아보았다. 그렇다면 노드는 브라우저를 끼고 있는것도 아닌데 동시성을 어떻게 보장받는 것인지 궁금해진다.

동시성 : 여러 작업이 마치 동시에 일어나는 것처럼 보이는것

Node.js는 V8엔진과 비동기 작업을 처리하는 libuv로 구성되어 있다. libuv를 보면 이벤트 루프, 태스크 큐와 같은 친숙한 친구들이 보인다. 하지만 브라우저 런타임에서 말하는 이벤트 루프와 노드의 이벤트 루프에는 다르다고 한다. 궁금하다면 Node.js의 동작 원리글을 참고해봐도 좋을 것 같다.

마무리

오늘은 자바스크립트에 연관된 것들을 나열하며 하나씩 알아보는 시간을 가졌다. 물론 자바스크립트에 대한 내용은 실제로 내용이 매우 방대하기 때문에 부족한 부분이 많을 것이다. 그래도 글을 작성하면서 평소에 헷갈렸던 개념들을 바로 잡아 좋은 시간이었다.

아! V8이 우리의 자바스크립트 소스 코드를 어떻게 해석하고 실행하는지 알아보고 싶다면 V8 엔진은 어떻게 내 코드를 실행하는 걸까?글을 추천한다!

profile
함께 일하고 싶은 개발자가 되기 위해 달려나가고 있습니다.

19개의 댓글

comment-user-thumbnail
2022년 9월 21일

좋은 글 잘 봤습니다!

1개의 답글
comment-user-thumbnail
2022년 9월 27일

글 잘 봤슴니당 👍👍👍

1개의 답글

진짜 이해하기 쉽게 잘 정리해 주셨네요! 덕분에 잘 학습하고 갑니다 :)

1개의 답글
comment-user-thumbnail
2022년 9월 27일

와 대박 너무 재밌고 유익해요^^

1개의 답글
comment-user-thumbnail
2022년 9월 28일

Hello there colleagues my site webhostingsoffer. This site gives us relative information from working with and figures out the thing is introduced on facilitating.
https://www.dreamgirldelhiescort.com/
https://www.delhiescortse.com/

답글 달기
comment-user-thumbnail
2022년 9월 30일

현호 스타 93개뭐냐
ㅋㅋㅋㅋㅋ

1개의 답글
comment-user-thumbnail
2022년 10월 4일

너무 쉽게 설명해주셨네요 잘보고갑니다!

1개의 답글
comment-user-thumbnail
2022년 10월 10일

좋은 글 잘 보고 갑니다! 감사합니다;-)

1개의 답글
comment-user-thumbnail
2022년 10월 25일

글 몇개 봤는데 진짜 잘쓰시네요
많이 배우고 갑니다!

1개의 답글
comment-user-thumbnail
2022년 11월 9일

이렇게 글 잘 쓰시는 분이 제 옆자리였군요 ㅎㅎ 잘 읽었습니다!

1개의 답글