[JS] 자바스크립트를 사용하는 이유

merci·2023년 8월 2일
0

JavaScript

목록 보기
8/15

웹 브라우저 동작 과정

브라우저에 검색을 한다고 해봅시다.

사용자는 브라우저의 인터페이스에 검색을 하게 됩니다.
엔터를 눌러 요청을 보내게 되면 브라우저 엔진이 입력된 URI를 렌더링 엔진에 전달합니다.
이때 브라우저 엔진은 로컬 스토리지에 캐싱된 데이터가 (이미지, 스크립트) 있는지 확인합니다.

렌더링 엔진은 로컬 스토리지를 통해 브라우저 엔진이 전달한 데이터가 없다면 서버에 요청을 보내게 되고
응답받은 데이터(html, css)를 파서를 통해 파싱 후 DOM트리를 만들어 메모리에 저장합니다.
그리고 자바스크립트는 인터프리터에 전달되어 DOM을 제어하게 됩니다 ( 동적 변화 )

브라우저의 렌더링 엔진은 html, css, js를 동기적으로 처리합니다.
렌더링 엔진은 보다 나은 사용자 경험을 위해 html, css 파서를 통해 파싱된 데이터를 즉각적으로 그리기 시작합니다.
즉 화면을 그리고 보여주면서 데이터를 전송받게 됩니다.

만약 스크립트를 <head>에 두게 된다면 브라우저는 화면 그리기를 중단하고 스크립트를 실행하게 됩니다.
화면이 그려지다가 잠시 멈추게 되면 사용자 경험이 나빠지게 되는데
심지어 스크립트가 외부 서버에 있다면 다운로드를 하는동안 렌더링 엔진이 멈추게 되어 사용자 경험이 더 나빠집니다.

또한 <head>에 위치한 스크립트가 DOM트리의 프로퍼티에 접근할 경우 존재하지 않는 요소이므로 에러가 발생하게 되고 스크립트는 더이상 실행되지 않고 브라우저는 동적인 기능을 잃게 됩니다.
따라서 </body>태그 이후에 스크립트를 추가하는게 권장됩니다.

</body> 태그 이후가 아닌 <head>태그 안에 <script>를 넣어야 한다면 아래의 옵션으로 렌더링 엔진이 멈추는 현상을 보완할 수 있습니다.


DOMContentLoaded

스크립트가 참조하는 DOM트리가 완성되지 않았을 때 접근하게 되면 에러가 발생합니다.
접근하려는 변수가 초기화 되지 않아서 발생하기 때문에 초기화 될때까지 기다렸다가 접근하기 위해 DOMContentLoaded 이벤트를 이용합니다.

DOMContentLoaded이벤트는 DOM트리가 완성된 후 다운받은 스크립트를 실행하는 순간 발생하는 이벤트로 아래와 같이 접근하게 되면 접근하는 대상이 존재하므로 에러가 발생하지 않습니다.

document.addEventListener("DOMContentLoaded", () => {
	
    document.querySelectorAll(".num_btn").forEach((btn) => {
		// ...
    });

따라서 스크립트가 실행하는 코드가 DOMContentLoaded 이벤트 리스너 안에 있다면 스크립트를
<head>태그 안에 넣어도 에러가 발생하지 않습니다.

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Calculator</title>
    <link rel="stylesheet" href="/static/cal.css">
    <script src="/static/cal.js"></script>
</head>

async

스크립트에 async속성을 추가하게 되면 브라우저는 html 파싱을 멈추지 않고 백그라운드에서 스크립트를 다운받습니다.
다운로드가 완료 되면 html 파싱이 완료되지 않더라도 곧바로 스크립트를 실행시켜 렌더링 엔진이 멈추는 단점이 있습니다.
여러개의 async 스크립트가 있다면 먼저 다운된 스크립트부터 실행됩니다.

<script async src="script.js"></script>

defer

지연 스크립트라고도 하는데 모든 DOM트리가 준비되면 발생하는 DOMContentLoaded 이벤트 전에 html 파싱이 완료된 후 실행됩니다.
async 와 마찬가지로 비동기적으로 스크립트를 다운받지만 html 파싱이 완료된 후 실행되며 여러개의 defer 스크립트가 있다면 위에 있는 스크립트부터 실행됩니다.
스크립트에 의존 관계가 있거나 순서가 보장되어야 할 경우 사용합니다.

<script defer src="script1.js"></script> 
<script defer src="script2.js"></script>


DOM 트리

DOM (Document Object Model): DOM은 웹 페이지를 프로그램이 이해하고 조작할 수 있는 구조로 변환하는 방법을 제공합니다.
이렇게 구성된 DOM 트리를 스크립트 언어로 동적으로 변경할 수 있습니다. ( 동적 기능 )

BOM (Browser Object Model): BOM은 웹 브라우저와 관련된 객체들을 조작하는 기능을 제공합니다.
BOM은 DOM을 포함하면서 브라우저와 관련된 객체들을 포함합니다.

이 두 가지 모델은 웹 페이지가 동적으로 동작하게 하는 핵심적인 기능을 제공하며, 웹 개발자들은 이 두 가지 모델을 이용해 사용자와 상호작용하는 웹 페이지를 만들 수 있습니다.

자바스크립트가 나온 이유

초기 웹 페이지는 정적인 콘텐츠를 제공했지만 사용자와 상호작용이 가능한 동적인 웹 페이지가 필요했습니다.
초기에는 로딩시간을 최소화하는게 중요했기 때문에 클라이언트의 브라우저에서 동작해 간단하게 처리되는 언어가 필요했습니다.

운영체제 위에서 새로운 프로그램을 만들기 위함이 아닌 이미 존재하는 소프트웨어를 제어하기 위한 용도로써
초기 브라우저인 넷스케이프에서 LiveScript를 ECMAScript 기반으로 표준화하고 자바스크립트라는 이름으로 출시했습니다.
이후 다른 브라우저에서도 자바스크립트를 지원하면서 표준 스크립트가 되었습니다.

자바스크립트의 이점

  • 쉽다.
    거의 모든 웹사이트 및 모바일 앱에서 자바스크립트를 사용합니다.

  • 플랫폼 독립성 확보
    자바스크립트는 모든 웹 페이지에 삽입, 다른 웹 개발 프레임워크 및 언어와 함께 사용 가능, 어떤 pc에서도 실행 가능합니다.

  • 서버 부하 감소
    예를들어 자바스크립트는 입력된 패스워드가 양식에 맞는지 클라이언트단에서 확인을 함으로서 서버에 요청을 보내지 않아 부하를 줄일 수 있습니다.

  • 동시성 지원
    여러 명령어 세트를 병렬로 실행 가능합니다.
    -> 비동기 처리 Callback, Promise, async/await, node.js (Worker Threads), 이벤트루프

자바스크립트의 한계

  • 타입이 명확하지 않고 유연하게 동작하므로 개발자의 의도와 다른 결과를 가져올 수 있습니다.

  • 자바스크립트는 인터프리터 언어로서 컴파일 언어에 비해 상대적으로 느립니다.
    ( 인터프리터는 캐싱이 안되서 모든 코드를 해석하지만 컴파일러는 캐시를 이용 )

최근에 브라우저는 JIT 컴파일러를 이용해서 최적화를 합니다.

JIT 컴파일

실행 중에 한줄씩 실행하는 인터프리트 방식과 실행 전에 전체를 바이트코드로 변환하는 컴파일방식이 합쳐진 방식입니다.
인터프리트 방식은 최적화하는 과정없이 변환하기 때문에 성능이 낮지만 빠르게 실행되고 컴파일 방식은 다양한 플랫폼에 맞게 컴파일 하기 때문에 컴파일 시간이 오래 걸리지만 성능이 우수합니다.

반복된 코드를 매번 변환하지 않기 위해서 브라우저는 인터프리터에 컴파일러를 접목시키기 시작했습니다.
JIT 컴파일러는 소스코드를 바이트 코드로 변환한뒤에 필요한 부분만 컴파일하여 실행 파일을 생성하고 나머지는 인터프리트 방식으로 바로 실행합니다.
반복되는 코드는 캐싱하여 같은 함수가 여러 번 불릴 때 매번 기계어 코드를 생성하는 것을 방지합니다.

하지만 자바스크립트 엔진인 브라우저의 인터프리터는 동적타입인 자바스크립트를 JIT컴파일러로 컴파일할때 모든 타입의 경우의 수를 기계어로 변환하지 않습니다.

대표적인 경우만 컴파일하고 나머지는 인터프리팅이 되는데 이렇게 되면 인터프리트 방식과 별 차이가 나지 않게 됩니다.
또한 초기 자바스크립트는 복잡한 기능을 수행하지 않아 반복적으로 수행되는 Hot Spot이 적기 때문에 캐싱의 이점을 찾기 어려웠습니다.

적응형 JIT 컴파일러

이러한 JIT컴파일러를 구글에서 개선해 V8 이라는 엔진을 만들게 되었습니다.


출처 : https://medium.com/@poojasharma_93670/sneak-peek-into-javascript-v8-engine-d2bb2eb2bdb2

V8은 소스코드를 AST로 만든뒤에 Ignition 컴파일러로 바이트코드로 변환합니다.
변환된 바이트코드는 TurboFan 컴파일러로 보내져 반복되는 부분인 Hot Spot을 찾아 최적화를 하게 됩니다.
이후 최적화된 코드가 바이트 코드에 반영되어 실행속도가 더욱 빨라지게 됩니다.
따라서 AJITC를 적용한 V8을 사용하는 브라우저는 복잡한 자바스크립트 코드도 빠르게 실행시킬 수 있습니다.


자바스크립트를 사용하는 이유

  • 자바스크립트는 인터프리터 언어이므로 전체 컴파일을 하지 않아 빠르게 결과를 확인할 수 있습니다.
    또한 V8 엔진이 스크립트를 최적화하므로 빠르게 응답해주고 오버헤드를 감소시킵니다.

  • 클라이언트 스크립트이기 때문에 서버에 부하가 적습니다.
    또한 서버에 요청을 보내지 않고도 클라이언트 단에서 데이터를 검증할 수 있습니다.

  • 매우 쉬운 언어이므로 비용이 적습니다.

  • 현대의 대부분의 브라우저가 지원합니다.

  • npm 등을 이용해 다양한 라이브러리를 쉽게 추가할 수 있습니다.

  • 백엔드에서도 Node.js를 통해 개발이 가능합니다.

profile
작은것부터

0개의 댓글