본문 바로가기

FrontEnd/Frontend-related basic knowledge

브라우저 동작 원리에 대하여

출처: https://velog.io/@wlwl99/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EA%B5%AC%EC%A1%B0

출처: https://www.youtube.com/watch?v=Mqh13dNI8jc

 

출처: https://poiemaweb.com/js-browser

자바스크립트해석기=자바스크립트엔진

 

사용자 인터페이스? 어려운거 아니고 그냥 이런거 말하는 거임
렌더링 엔진? 웹사이트를 그리는 엔진. Rendering=그리다의 의미로 사용됨

브라우저 엔진이란? 사용자 인터페이스와 렌더링 엔진의 교두보 역할. 예를들어 인터페이스로 뒤로가기 버튼 눌렀다면 이전의 페이지를 가져오라는 명령을 하는 것이 브라우저 엔진이고 그 명령을 실행하는 것이 렌더링 엔진!

 

웹브라우저의 네트워크 부분을 담당

 

우리가 자바스크립트를 배우는 이유!! 브라우저는 자바스크립트를 이해할 수 있음

UI백엔드: 사용자와 소통하는 부분. 예를들면 사용자 입력, 마우스 움직임, 클릭을 핸들링

자료저장소? 브라우저가 필요한 정보를 저장해 놓는 곳. 예를들면 로컬스토리지, 세션스토리지, 쿠기 등

웹브라우저는 하나의 작은 OS와 같음.

 

위 그림에서 랜더링엔진을 좀더 살펴보자(렌더링 엔진의 최종목표는 Render Tree그리는 것인거같음. 내생각). 브라우저는 어떻게 화면을 그리는 걸까? 우리가 인터넷 주소를 입력한다고 브라우저는 그것을 알수없다. 브라우저가 이해하는 것은 IP주소이다.주소를 입력하면 DNS(Domain Name System)를 거쳐 해당주소의 IP주소를 얻어옴(이 IP주소를 얻는 과정이 단순하지가 않음).얻어온 주소는 DNS cache에 저장하여 다음에는 따로 DNS에 묻는 과정을 없앰.그 후 얻어온 IP주소에 해당하는 서버로 가서 웹페이지를 요구함. 이때 서버로 부터 얻는 페이지의 내용을 인코딩하여 브라우저로 가져오고 브라우저는 그 인코딩된 내용을 디코딩한다. 그렇게 디코딩하여 얻어낸 문자들을 가지고 Token을 만들어낸다. 이 토큰화과정을 가치면 비로써 우리가 알아볼수 있는 문서(Document)가 생김. 브라우저는 이 문서를 하나씩 하나씩 읽음(like, 아 head태그구나, body태그구나 하면서). 이 과정을 Tokenizer(토큰화)과정이라고함. 즉 브라우저가 문서를 읽고 토큰이라는 결과물들을 만들어내는 것임.  마치 아래 그림처럼.

그후 토큰들을 의미있는 단위로 해석하게 됨. 그 의미있는 단위가 객체임. 그리고 이 객체를 "노드" 라고 부른다.

(그런데 토큰과 노드의 다른점이 정확히 뭐지? 아래그림에서보면 토큰과 노드가 다르지 않게 느껴지는데...)

그 후 노드의 관계를 정리하여 트리형식의 DOM구조로 묶어냄. 참고로 노드간의 관계를 부여해 주면 그것을 MODEL이라고 함. DOM 트리의 M이 Model임. DOM=Document Object Model 아... DOM에서 말하는 Document가 그 태그들간의 위계관계가 있는 html문서이고 Object가 Node이고 Model이 DOM TREE를 말하는 것이구나!!!즉 DOM이란 HTML문서(Document)에 있는 위계관계가 있는 노드(Object)를 트리형식의 모형(Model)으로 만든것이 DOM이다!!!여기까지가 랜더링과정에서 HTML문서가 그려지는 과정이었다. 즉, 랜더링과정에서 HTML문서는 최종적으로 트리 모형으로 그려지게 된다. 

(유니코드란? 사람이 알아볼수 있는 글자 각각을 코드화시킨것. 예를들어 한글 '가'의 유니코드는  ‘U+AC00’ 이다. 이 유니코드(국제표준문자)를 컴퓨터가 이해할 수 있는 형태인 0과 1로 바꾸어 주는 것을 인코딩(encoding)이라고함. UTF-8인 유니코드를 인코딩하는 방식의 하나이다.  보통 인간이 볼수 있는 문자열을 UTF-8로 인코딩한다는 말을 볼수 있는데 이런말은 문자열=> 유니코드 => 0과1 로 인코딩하는 과정에서 유니코드에 대한 언급을 빼고 문자열을 (0과1로) 인코딩한다는 의미이다. )

 

그렇다면 CSS문서는 어떻게 랜더링되어 지는가?

HTML문서를 읽으면서 CSS와 관련된 link태그를 만나면 기존에 가지고 있었던 웹서버 주소라 다시 찾아감. 그리고 해당 style.css파일을 요구함. 그리고 이전에 HTML에서 했던 과정처럼 파일의 내용을 인코딩, 디코딩후

이 과정을 CSS또한 HTML처럼 모두 똑같이 겪고 그 결과물로 CSSOM(쏨) tree를 그리게 됨.

CSSOM!!!(CSS Object Model)

 

이제 마지막으로 html문서를 읽으면서 js파일이 필요한 것이고

다시 서버에게 가서 js파일을 요구함.

Javasrcipt는 매우 강력함. 무슨 말이냐면 HTML문서로부터 DOM트리를 그리는 와중에 위와 같은 <script src="main.js"> </script>를 만나면 그리고 있던 DOM파싱을 중단시킴. 왜냐하면 자스로 DOM트리까지 그릴수 있기때문임(아래 그림은HTML이 Build DOM을 하는 와중에 자스문서가 호출되면 DOM파싱이 중단(blocked)되는 것을 보인것임). 즉 자스만으로도 노드를 만들수 있기 때문에 굳이 자신만의 세계에서 DOM 트리 구성해도 자스에 의해 다시그려져야 하므로 효율성 측면에서 멈추게 되는 것임.

 

실제 아래와 같은 코드가 있다.

main.js 안에는 아래와 같은 코드가 있음.

첫번째로 주목할 것이 문법의 틀을 지키지 않고 이 그림 위의 그림에서 script태그가 div이전에 왔음. , div태그에 관한 노드가 DOM트리의 일부로 그려지기 전에 자바스크립트 코드가 호출된 것임. 그리고 그 JS코드 안에서 div안의 내용인 hey를 바꾸라고 하는 명령어가 document.getElementById~~~~;코드임. 결국은 에러남. 왜? id가"test"라는 코드는 아직은 없는 코드이기&nbsp; 때문이다. 이러한 이유로 많은 사람들이 script태그는 바닥에 두라고 하는 것입니다.

 

하지만 아래와 같은 인위적인 설정(defer)으로 자스의 코드가 DOM파싱을 막지 않게 해줄수 있다.

defer, async 라는 명령어가 있으면 스크립트 파일이 DOM의 생성을 막지 않습니다.

여기서 알수 있는것! 자스파일의 호출은 DOM생성을 방해하므로 HTML파일의 바닥부분script 태그를 두는것이다. 그렇다면 css관련태그는 왜 가장 위에 둘까? 당연하게도 css는 DOM의 생성을 막지 않기 때문이다. 그래서 HTML파일의 상위에 둘수 있는 것임.

DOM은 CSSOM이 다 끝날때 까지 기다림. 따라서 CSS파일이 너무크면 웹사이트의 성능에 많은 영향을 끼침. 만약 CSS가 너무 크면 DOM은 매우 많이 기다려야함. 따라서 CSS파일의 크기를 줄이는 여러가지 방법이 있다.

1. media쿼리 이용. screen사이즈에 따라서 다른 스타일을 가져올 수 있음. 예를들어 사용자에게 desktop화면만 보여주면 되는 경우에 모바일 버전의 스타일을 가져올 필요가 없는 것임.

위와 같이 DOM트리 그리고 CSSOM트리가 만들어 졌으면 이것을 통합하여 랜더트리를 만듦.

Render Tree. 말그대로 그릴 준비가 된 트리임. 웹사이트를 그리기 위한 최종트리임. 따라서 쓸데없는 요소는 Render Tree에서 제외된다. 예를들어 head태그, meta태그 등은 화면을 그리는데 사용되지 않으므로 과감히 Render Tree에서 제거된다. 그리고 위의 CSSOM트리에서 span의 속성 display는 none이다. 즉 보이지 않으므로 굳이 화면을 실제로 그리는 설계도인 Render Tree에서는 빠지게 된다.

Render Tree가 완성되면 그 완성된 트리를 가지고 여러장의 종이에다가 그것을 그리는데 그 각각의 종이를 layout이라고 생각하면됨. 그 후 그 각각의 페이지에 painting을 한후에 painting된 여러페이지(layout)를 합쳐서 최종 완성본인 Composite이 나옴.

시중에 여러 자료가 있어서 하나더 가져왔음

하지만 이렇게 하나의 페이지가 완성이 되었다고 해서 끝나는 것이 아니라 내가 어떤 변경을 주면 그것을 페이지(layout)에 반영하기 위해 다시 layout단계로 돌아가고 다시 그것을 composite하여 화면에 그리는 것이다. 그리고 이 과정을 변경이 있는 동안 계속적으로 반복하게 되는 것(내 생각에는 지금 이 과정이 AJAX를 말하는 것 같다. 즉 Asynchronous Javascript And XML로써 화면의 특정 부분이 바뀌면 전체를 다시 서버로부터 가져오는 것이 아니라 변경에 해당하는 부분만을 가져와서 성능을 향상시키는 것).

Layout이 다시 그려질때 즉, Reflow되는 경우는 아래와 같다.

참고로 페이지를 다시 그리는 것이므로  layout이 바뀌는 경우는 비용이 듭니다.

그렇다면 빠른 랜더링(웹사이트 성능향상)을 위해서는 어떻게 해야하나?

오직 특정페이지에만 적용되는 css를 가져오는 경우 style.css라고 해서 link를 걸어두는 것보다 인라인으로 하는게 더 좋습니다. Reflow=layout다시 가져오는 것. Repaint=말그대로 다시 css작업하는 것
left, right가 들어간경우 Reflow를 하므로 비용이 비싸짐. 따라서 transition같은 것을 이용하는게 더 좋음.

이상으로 랜더링 과정을 살펴보았다.

===========================================================================================

구글의 Chrome V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임 환경(Runtime Environment)인 Node.js의 등장으로 자바스크립트는 웹 브라우저를 벗어나 서버 사이드 애플리케이션 개발에서도 사용되는 범용 개발 언어가 되었다. 하지만 자바스크립트가 가장 많이 사용되는 분야는 역시 웹 브라우저 환경에서 동작하는 웹 페이지/애플리케이션이다.

대부분의 프로그래밍 언어는 운영체제(Operating System, OS) 위에서 실행되지만 웹 애플리케이션의 자바스크립트는 브라우저 위에서 HTML, CSS와 함께 실행된다. 따라서 브라우저 환경을 고려할 때 보다 효율적인 자바스크립트 프로그래밍이 가능하다.

브라우저의 핵심 기능은 사용자가 참조하고자 하는 웹페이지를 서버에 요청(Request)하고 서버의 응답(Response)을 받아 브라우저에 표시하는 것이다. 브라우저는 서버로부터 HTML, CSS, Javascript, 이미지 파일 등을 응답받는다. HTML, CSS 파일은 렌더링 엔진의 HTML 파서와 CSS 파서에 의해 파싱(Parsing)되어 DOM, CSSOM 트리로 변환되고 렌더 트리(Render Tree)로 결합된다. 이렇게 생성된 렌더 트리를 기반으로 브라우저는 웹페이지를 표시한다.

이 그림에서말하는 Javascript Engine이 이 그림위에있는 그림에서의 자바 스크립트 해석기같음. 즉 해석해 보자면 자스관련코드는 DOMAPI의 도움을 받아서 Dom tree와 CSSOM tree와 합쳐져서 최종적으로 Render Tree를 만드는 것 같음.&nbsp; 또한 위 그림에서처럼 clinet와 server사이에 html,css, js 파일을 받기 위한 과정이 차례로 진행되고 있는 것을 볼수 있다.

 

자바스크립트는 렌더링 엔진이 아닌 자바스크립트 엔진이 처리한다. HTML 파서는 script 태그를 만나면 자바스크립트 코드를 실행하기 위해 DOM 생성 프로세스를 중지하고 자바스크립트 엔진으로 제어 권한을 넘긴다. 제어 권한을 넘겨 받은 자바스크립트 엔진은 script 태그 내의 자바스크립트 코드 또는 script 태그의 src 어트리뷰트에 정의된 자바스크립트 파일을 로드하고 파싱하여 실행한다. 자바스크립트의 실행이 완료되면 다시 HTML 파서로 제어 권한을 넘겨서 브라우저가 중지했던 시점부터 DOM 생성을 재개한다.

이처럼 브라우저는 동기(Synchronous)적으로 HTML, CSS, Javascript을 처리한다. 이것은 script 태그의 위치에 따라 블로킹이 발생하여 DOM의 생성이 지연될 수 있다는 것을 의미한다. 따라서 script 태그의 위치는 중요한 의미를 갖는다.

body 요소의 가장 아래에 자바스크립트를 위치시키는 것은 좋은 아이디어이다. 그 이유는 아래와 같다.

  • HTML 요소들이 스크립트 로딩 지연으로 인해 렌더링(그리는 작업)에 지장 받는 일이 발생하지 않아 페이지 로딩 시간이 단축된다.
  • DOM이 완성되지 않은 상태에서 자바스크립트가 DOM을 조작한다면 에러가 발생한다.