회고록 블로그

[브라우저 공부] 브라우저에서의 HTML+CSS(+JS) 작동 방식 공부하기 (3) 본문

2. 프로그래밍 언어 공부/HTML+CSS

[브라우저 공부] 브라우저에서의 HTML+CSS(+JS) 작동 방식 공부하기 (3)

김간장 2022. 4. 7. 19:22

이전글 참고하기

2022.04.07 - [2. 개발 공부/HTML+CSS] - [브라우저 공부] 브라우저에서의 HTML+CSS 작동 방식 공부하기 (2)

 

[브라우저 공부] 브라우저에서의 HTML+CSS 작동 방식 공부하기 (2)

이전글 참고하기 2022.04.07 - [2. 개발 공부/HTML+CSS] - [브라우저 공부] 브라우저에서의 HTML+CSS 작동 방식 공부하기 (1) [브라우저 공부] 브라우저에서의 HTML+CSS 작동 방식 공부하기 (1) ※ 필자는 초초

cinnamonc.tistory.com

 

※ 필자는 초초초보자입니다. 틀린 내용은 언제든지 피드백 부탁드립니다.

 

 

HTML, CSS, 이미지 파일 등을 통해 웹 페이지를 화면에 보여주는건 동작 방식을 어느정도 이해했지만 그 동작 방식에 자바스크립트는 빠져 있었다.

그래서 별도로 찾아서 공부를 했다.

 

기본적으로 공부하면서 참고한 자료는 아래 두 개의 글이다.

출처1 : https://pstudio411.tistory.com/entry/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC

출처2 : https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/


✅ 브라우저에서의 자바스크립트 동작


❖ 앞의 내용 간단 정리

앞의 글에서 렌더링 엔진(rendering engine)의 동작 원리와 화면에 콘텐츠를 보여주기 위한 과정에 대해 공부하면서

1) 서버에 요청(request)을 해서 내용 받고(응답 받음)

2) HTML 문서를 파싱해서 DOM 트리로 변환하고

3) CSS 파일을 파싱해서 CSSOM 트리로 변환한 후

3) 두 개의 트리를 결합하여 렌더 트리(render tree)를 생성하고

4) 배치와 그리기를 수행한다고

정리했었다.

 

❖ 자바스크립트 엔진

JavaScript는 [렌더링 엔진]이 처리하지 않고 [자바스크립트 해석기]가 처리한다.

참고로 자바스크립트 해석기 혹은 자바스크립트 엔진(javascript engine)은 대표적으로 아래와 같다.

‣ 구글(google)의 크롬 : V8

‣ 애플(apple)의 사파리 : 웹킷

‣ 모질라(mozila) 재단의 파이어폭스 : 스파이더몽키

 

❖ 자바스크립트의 렌더링 시기

1) HTML을 파싱하는 과정에서 파서(parser)가 HTML의 <script> 태그를 만나면

     자바스크립트 코드를 실행하기 위해 DOM 생성 프로세스를 일시 중지하고

2) 자바스크립트 엔진(자바스크립트 해석기)에게 제어 권한을 넘긴다.

3) 자바스크립트 엔진(JavaScript engine)의 실행이 끝나면 브라우저는 중단된 부분부터 다시 시작하여 DOM 구성을 재개한다.

    ‣ 자바스크립트 엔진의 동작 원리는 #별첨1을 참고

(출처 : 상단 출처1, 출처2 참고)

 

자바스크립트 엔진이 동작하는 시기가 이렇게 구성되어 있는건 JavaScript의 특성 때문이다.

기본적으로 JavaScript는 페이지가 작동하는 방식의 거의 모든 측면을 변경할 수 있다.

   ‣ HTML 문서의 내용을 수정할 수도 있고 CSS를 수정(폰트 색상 변경 등)할 수도 있다.

즉, 앞서 공부했던 DOM트리와 CSSOM 트리를 수정할 수 있다는 의미라고 한다.

(출처 : 상단 출처2 참고)

 

'DOM 트리에서 요소를 추가/제거하는 등 수정'할 수 있으며 'CSSOM 속성을 수정하는 것'도 할 수 있기 때문에

트리(tree)를 변환하는 과정에서 자바스크립트 엔진이 동작하는 것이다.

 

 

❖ 이때 주의할 점

자바스크립트 엔진이 동작하는 시기가 "HTML 파싱" 과정이다보니

DOM 생성이 차단되어서 초기 렌더링하는 과정이 지연될 수 있다고 한다.

(출처: 상단 출처2 참고)

 

앞서 [렌더링 엔진]에 대해서 공부하면서 이런 내용도 함께 공부했었다.

     ‣ 렌더링 엔진은 (가능하면 빠르게 사용자에게 내용을 표시하기 위해서) 모든 HTML을 파싱할 때까지 기다리지 않고
        배치(리플로)와 그리기 과정을 시작한다.

브라우저는 기본적으로 빠르게 내용을 표시하기 위해서 모든 HTML 문서를 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작하는데, <script> 태그로 묶인 자바스크립트를 실행하느라 렌더링이 지연되는 문제가 생기는 것이다.

따라서 렌더링하는데 상당한 지연이 발생할 수 있다.

 

여기에 DOM 트리 뿐만 아니라, CSSOM 트리까지 들어오면 더 성능이 나빠진다.

만약 스크립트(script)를 실행하려고 할 때, CSSOM 다운로드 및 빌드가 완료되지 않으면

브라우저는 CSSOM 다운로드 및 구성을 완료할 때까지 스크립트 실행과 DOM 구성을 지연시킨다고 한다.

(출처 : 상단 출처2 참고)

 

자바스크립트 파일이 외부 파일인 경우, 서버에 파일을 요청하고 응답 받아야 하기 때문에 더 지연될 수 있다.

 

❖ 때문에 알아둬야 할 점

1) 이 때문에 <script> 태그를 HTML 문서의 <body> 태그 하단에 위치시키거나

2) <script 태그의 속성으로 async 를 사용한다

     ‣ 만약 렌더링 엔진이 <script src="script.js" async></script> 코드를 만나면

        스크립트를 사용할 수 있을 때까지 기다리는 동안

        DOM 생성을 차단하지 않도록 지시하기 때문에 성능 향상에 도움이 된다고 한다.

(출처 : 상단 출처2 참고)

 

 


⚠️ 별첨1. 자바스크립트 엔진의 동작 원리


자바스크립트 엔진은 Memory HeapCall Stack으로 구성되어 있다.

 

❖ 메모리 힙(memory heap)?

변수나 함수를 저장하는 공간이다. 저장한 데이터를 불러와야 할 때(호출할 때) 메모리 힙에 저장된 주소를 가져온다.

❖ 콜스택(call stack)?

코드를 한줄씩 읽어 내려가면서 수행할 작업들을 밑에서 부터 하나씩 쌓는 공간이다.

자세한 내용은 https://cinnamonc.tistory.com/313?category=926475 를 참고하자.

엔진 내부에 메모리(memory heap, call stack)만 있다는 것은 아니고

파서(parser), 인터프리터(interpreter), 컴파일러(compiler) 등의 기능도 자바스크립트 엔진(JavaScript Engine) 안에 구현되어 있다.

 

아래 그림은 Node.js 내부에 작성된 JavaScript 코드 실행 방법에 대한 그림이지만, 과정은 유사하다.

또한 자바스크립트를 동작하는 방식은 크롬의 엔진인 V8을 기준으로 작성하려고 한다.

(공부한게 그것 밖에 없다.. 참고로 브라우저, 버전별로 약간씩 과정은 다를 수도 있다)

 

그림 출처 :&nbsp;https://www.geeksforgeeks.org/what-is-the-relationship-between-node-js-and-v8/

 

1) 자바스크립트 소스코드를 가져와 파서(parser)에게 넘기고 파싱한다.

     ‣ 이때, 파싱하여 AST(추상 구문 트리; Abstract Syntax Tree)로 변환한다.

     ‣ 앞에서 공부했었던 [HTML 문서를 파싱해서 구문 트리(syntax tree)로 변환]하는 것처럼 자바스크립트 소스코드 또한 그렇게 트리 구조로 변환한다.

     ‣ 참고로 추상 구문 트리(AST)는 아래와 같이 트리 구조로 되어 있다.

        이 그림은 사람이 보기 좋은 형태로 예쁘게 색칠한(?) 것일 뿐 실제로 컴퓨터는 이렇게 예쁘게 색칠하며(?) 변환하지 않는다.

출처 : 위키백과;&nbsp; https://ko.wikipedia.org/wiki/%EC%B6%94%EC%83%81_%EA%B5%AC%EB%AC%B8_%ED%8A%B8%EB%A6%AC

 

     ‣ AST를 잘 알아두면 개발 라이프가 재미있어(?) 질 수 있다는 이야기가 있다.

     ‣ AST가 생성되는 것이 궁금하다면 AST 파서를 실행할 수 있는 실시간 에디터(https://astexplorer.net/)를 통해 확인해봐도 좋다고 한다.

 

2) 생성된 AST는 인터프리터(interpreter) 혹은 컴파일러(compiler)에게 전달되며 바이트코드(byte code)로 변환한다.

     ‣ 바이트 코드(byte code)는 intermediate code라고 한다.

        고레벨 언어와 기계코드(0, 1로 된 코드)의 중간 코드라고 해석할 수 있다.

     ‣ 만약 임의의 엔진이 컴파일러(compiler)를 사용한다면, C언어에서 배운 컴파일 과정이 이에 해당한다.

     ‣ 컴파일러와 인터프리터의 상세한 차이점은 이 글(https://soldonii.tistory.com/52)을 확인하자.

        모두 설명하기엔 너무 길어져서 생략하기로 했다.

     ‣ 구글 크롬의 자바스크립트 엔진 'V8'에서는 인터프리터를 사용하는데,

        이 인터프리터의 명칭이 Ignition이라고 한다.

 

3) 바이트 코드(byte code)를 최적화된 기계 코드(machine code)로 변환하고 실행한다.

     ‣ 그냥 기계코드로 변환해서 실행하는 것이 아니다.

     ‣ 크롬 엔진인 'V8'에는 더 빠르고 효율적으로 자바스크립트를 해석하고 실행할 수 있도록

        최적화된(optimize) 컴파일러를 포함하고 있다.

       (구글의 최적화 컴파일러의 명칭은 Turbofan인데, 일반적으로는 JIT Compiler라고 부르는 듯 하다)

     ‣ 여기에서 말한 [최적화된 컴파일러]가 최적화된 기계 코드를 생성하는 것이다.

 

 

3)의 과정을 좀 더 세세하게 나눠서 알아보자.

공부 자료의 출처는 하단의 [출처3]과 [출처4]를 보면 된다.

 

그림 출처 :&nbsp;https://stackoverflow.com/questions/54957946/what-does-v8s-ignition-really-do

 

3-1) 인터프리터가 코드를 실시간(한줄씩)으로 바이트 코드(byte code)로 변환하는데

         이때 프로파일러(profiler)가 최적화할 수 있는 부분을 찾아서 기록해놓는다.

         ‣ 코드를 한줄씩 실행시키면서 유독 어떤 함수가 많이 실행되면

            그  함수를 최적화를 위해서 그 부분을 기록해놓는다고 한다 (출처4 참고)

 

3-2) 최적화 가능한 부분을 찾으면 프로파일러는 컴파일러에게 이를 전달하고,

         컴파일러는 최적화를 진행한다. (최적화된 기계 코드를 생성)

         ‣ 즉, 반복되는/동일한 작업을 계속 기계 코드로 여러번 변환하는건 비효율적이니

            속도 향상 등을 위해 불필요한 동작을 제거하는게 [최적화]다.

         ‣ 이 과정에서 최적화된 기계 코드가 생성된다.

 

3-3) 만약 최적화한 코드의 수행 차례가 다가오면, 바이트 코드(byte code) 대신에

         최적화된 기계 코드를 그 자리에 대체하여 실행된다.

 

 

출처1 : https://soldonii.tistory.com/52

출처2 : https://gyujincho.github.io/2018-06-19/AST-for-JS-devlopers

출처3 : https://www.geeksforgeeks.org/what-is-the-relationship-between-node-js-and-v8/

출처4 : https://dongwoo.blog/2017/06/06/%EB%B2%88%EC%97%AD-%EC%A0%80%EC%8A%A4%ED%8A%B8-%EC%9D%B8-%ED%83%80%EC%9E%84jit-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EC%A7%91%EC%A4%91-%EC%BD%94%EC%8A%A4/

 

 

Comments