페이지 렌더링 속도 - peiji lendeoling sogdo

브라우저는 사용자가 선택한 자원을 해당 서버에 요청하고 브라우저 위에 표시한다. 브라우저가 서비스 페이지를 보여주기 위해서는 DOM 및 CSSOM 트리가 생성되어야 한다. 트리를 생성하기 위해서는 서버로 부터 HTML과 CSS를 제공받아야 한다.

브라우저에 페이지를 그리는 과정은 아래와 같이 정리해 볼수 있겠다.

  • HTML 마크업은 DOM(Document Object Model)으로 변환 된다.
  • CSS 마크업은 CSSOM(CSS Object Model)으로 변환 된다.
  • DOM과 CSSOM은 결합되어 렌더링 트리를 구축한다.

페이지 렌더링 속도 - peiji lendeoling sogdo

 

 

 

  • Send Request
    - index.html에 대한 GET 요청을 전송한다.
  • Parse HTML & Send Request
    - 전달 받은 HTML을 파싱한다.
    - style.css와 main.js에 대한 GET 요청을 전송한다.
  • Parse Stylesheet
    - CSS를 파싱한다.
  • Evaluate Script
    - 전달 받은 main.js를 실행한다.
  • Layout
    - HTML의 메타 뷰포트 태그를 기반으로 레이아웃을 배치한다.
  • Paint
    - 화면에 페인트한다.

 

 

 

CSS 최적화

CSS는 렌더링 차단 리소스(render blocking resource)다. 즉, CSSOM이 생성될 때까지 브라우저는 렌더링하지 않는다.

최초 렌더링에 걸리는 시간을 최적화하기 위해서는 CSS를 간단하게 만들고 클라이언트에 최대한 빠르게 다운로드 되어야 한다.

 

  • 간결한 selector 사용
    - 덜 구체적인 선택자는 더 구체적인 선택자보다 더 빠르다.
    - 예를 들어, 브라우저가 .foo 찾을 때, .foo {} .bar .foo {} 보다 빠르다.
    - 왜냐하면 .bar .foo {} 의 경우, .foo가 부모 객체인 .bar를 가지고 있는지 확인하기 위해 DOM을 거슬러 올라가기 때문이다.
    <div class="container">
      <ul class="list">
        <li>
          <button type="button" class="btn">버튼</button>
        </li>
        <li>
          <button type="button" class="btn">버튼</button>
        </li>
      </ul>
    </div>
    // bad 
    .container .list li .btn {
      background-color: red; 
    } 
    
    // good 
    .list .btn { 
      background-color: red; 
    }
  • 미디어 유형과 미디어 쿼리 사용
    <link rel="stylesheet" href="style.css" /> // blocking
    <link rel="stylesheet" href="style.css" media="all" /> // blocking, 미디어 유형 사용
    <link rel="stylesheet" href="print.css" media="print" /> // non blocking, 미디어 유형 사용
    <link rel="stylesheet" href="portrait.css" media="orientation: landscape" /> 
    // non blocking, 미디어 쿼리 사용으로 기기의 방향이 가로일 때만 렌더링 차단
    <link rel="stylesheet" href="mobile.css" media="screen and (max-width: 480px)" /> 
    // non blocking on large screens, 미디어 쿼리 사용으로 기기의 너비 조건이 일치 시 렌더링 차단

    - 페이지 인쇄 or 모바일 출력의 경우 등 특정 조건에 사용되는 CSS가 있다면 미디어 유형과 미디어 쿼리를 사용해 CSS 리소스를 렌더링 비차단 리소스로 표시할 수 있다.
    - 미디어 쿼리(media) 기반으로 CSS를 여러 파일로 분할하면, 사용하지 않는 CSS를 다운로드만 하고 렌더링을 차단하진 않는다.

 

JavaScript 최적화

  • 자바스크립트 파서 차단 리소스(parser blocking resource)다.
  • 웹은 파싱과 실행이 동시에 수행되는 동기화(synchronous) 모델이기 때문에 <script> 태그를 만나면 진행하던 HTML 파싱을 중지하고 자바스크립트 엔진에게 권한을 넘겨 자바스크립트를 다운, 파싱, 실행한다.
  • <script> 태그 다운, 파싱  >>  <script> 태그 실행  >>  실행 완료 후 다음 태그 파싱
  • 이러한 이유로, 일반적으로 <body> 태그를 닫기 직전에 <script> 태그를 선언한다.
  • HTML5에서는 <script> 태그를 비동기적으로 처리하는 속성(async, defer)이 추가되었다.

   

1) <head> 안에 <script>가 위치해 있는 경우

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <script src="main.js"></script>
  </head>
  <body></body>
</html>

 

페이지 렌더링 속도 - peiji lendeoling sogdo
  • 파싱 중 <script> 태그를 만나면 html 파싱을 멈추고 해당 자바스크립트 파일(main.js)을 서버에서 다운받아 곧바로 실행한다.
  • 단점 : 실행된 파일이 완료될 때까지 html 파싱이 멈추기 때문에, 자바스크립트 파일의 크기가 크거나 인터넷이 느린 상황일 경우 사용자가 웹사이트를 보는데까지 많은 시간이 걸린다.

   

2) <body> 안에, 끝부분에 <script>가 위치해 있는 경우

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <div></div>
    <script src="main.js"></script>
  </body>
</html>

 

페이지 렌더링 속도 - peiji lendeoling sogdo
  • <body> 안에서도 끝부분에 위치해 있기 때문에 사용자가 기본적인 html 콘텐츠를 상대적으로 빨리 불 수 있다.
  • 단점 : 자바스크립트에 많이 의존하는 웹사이트의 경우 

   

3) <head> 안에 <script> 위치 + async 속성 사용

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <script async src="main.js"></script>
  </head>
  <body></body>
</html>

 

페이지 렌더링 속도 - peiji lendeoling sogdo
  • async는 boolean 타입의 속성값이기 때문에 선언하는 것만으로도 true로 설정된다.
  • 파싱 중 async 속성을 가진 <script> 태그를 만나면 병렬적으로 자바스크립트 파일을 다운받게 된다.
  • 즉, 자바스크립트 파일 다운이 완료되기 전까지 HTML 파싱을 계속 진행하다가 다운이 완료되면 파싱을 멈추고 다운된 자바스크립트 파일을 실행한다.
  • 장점 : fetching이 병렬적으로 진행되기 때문에 이전에 소개한 방법들 보단 다운로드 받는 시간 절약 가능
  • 단점 : 페이지 준비 시간이 상대적으로 절약되긴 하지만 여전히 자바스크립트 파일 실행 중에는 HTML 파싱이 멈추게 된다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <script async src="aaa.js"></script>
    <script async src="bbb.js"></script>
    <script async src="ccc.js"></script>
  </head>
  <body></body>
</html>

 

페이지 렌더링 속도 - peiji lendeoling sogdo
  • async 속성을 가진 다수의 script를 다운 받게 되면, 먼저 다운받은 script를 우선적으로 실행한다.
  • bbb.js  >>  aaa.js  >>  ccc.js
  • 단점 : 웹사이트의 자바스크립트가 순서에 의존적인 경우, 원하는 순서로 자바스크립트 파일을 조작이 어렵다.

   

4) <head> 안에 <script> 위치 + defer 속성 사용 -> 가장 선호하는 방법

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <script defer src="main.js"></script>
  </head>
  <body></body>
</html>

 

페이지 렌더링 속도 - peiji lendeoling sogdo
  • async와 같이, 파싱 중 defer 속성을 가진 <script> 태그를 만나면 병렬적으로 자바스크립트 파일을 다운 받게 된다.
  • async와 다른 점은 HTML 파싱이 다 마친 후 자바스크립트 파일을 실행한다는 점이다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <script defer src="aaa.js"></script>
    <script defer src="bbb.js"></script>
    <script defer src="ccc.js"></script>
  </head>
  <body></body>
</html>

 

페이지 렌더링 속도 - peiji lendeoling sogdo
  • defer 속성을 가진 다수의 script를 다운 받게 되면 async와는 다르게, 다운 받는 순서와 상관 없이 파싱 순서에 따라 실행하기 때문에 원하는 순서에 맞게 조작이 가능하다.

 

언제 async를 사용하면 될까?

  • 스크립트 파일에 종속성이 없는 경우
  • async는 스크립트 리소스가 다운로드 완료되면 HTML 파싱을 중단하고 스크립트가 실행되기 때문에, 어느 시점에 HTML 파싱이 중단될지 보장할 수 없다.
  • 그러므로 DOM에 종속성이 없어서 HTML 파싱 중 어느 시점에 스크립트가 실행되든지 상관없을 경우 async 속성을 사용하는 것이 좋다.

 

언제 defer를 사용하면 될까?

  • async와 반대로 종속성이 있는 경우
  • DOM과 종속성이 있어서, DOM이 전부 생성되어야 정상적인 동작을 할 수 있는 경우
  • 다수의 스크립트 간에 종속성이 있어서, 스크립트 실행 순서가 항상 <script> 정의 순서로 실행되어야 하는 경우

 

리소스 우선순위 지정

브라우저에게 리소스 우선순위 전달함으로써 최적화할 수 있다.

 

preload 속성

  • 현재 페이지에서 빠르게 가져와야 하는 리소스에 사용되는 속성이다.
<div class="container">
  <ul class="list">
    <li>
      <button type="button" class="btn">버튼</button>
    </li>
    <li>
      <button type="button" class="btn">버튼</button>
    </li>
  </ul>
</div>
0
  • 주의사항
    - as 속성을 사용하여 리소스의 유형을 브라우저에게 알려줘야 한다.
    - preload 속성은 리소스를 반드시 가져오기 때무에 리소스가 중복되지 않도록 해야 한다.
    - 현재 페이지에서 반드시 사용되는 리소스에만 사용해야 한다.

  • 브라우저 지원 현황
페이지 렌더링 속도 - peiji lendeoling sogdo

prefetch 속성

  • 현재 페이지 로딩이 마친 후 사용 가능한 대역폭이 있을 때(다운로드할 여유가 생겼을 때) 가장 낮은 우선순위로 리소스를 가져온다.
  • 브라우저는 미래에 사용될 리소스들을 가져와 캐시에 저장한다.
<div class="container">
  <ul class="list">
    <li>
      <button type="button" class="btn">버튼</button>
    </li>
    <li>
      <button type="button" class="btn">버튼</button>
    </li>
  </ul>
</div>
1
  • 주의사항
    - 위의 코드가 동작했을 경우, subPage.html 리소스는 가져오지만 subPage.html에서 사용되는 CSS 등의 리소스들은 가져오지 않는다.

  • 브라우저 지원 현황
페이지 렌더링 속도 - peiji lendeoling sogdo

 

요약

초기 렌더링 최적화 

브라우저가 페이지의 초기 출력을 위해 실행해야 하는 순서인 CRP를 최적화함으로써 초기 렌더링을 최적화할 수 있다.

  • CSS 최적화 : 미디어 유형, 미디어 쿼리 사용
  • JavaScript 최적화 : <body> 태그 닫기 직전에 <script> 태그를 선언하거나 async, defer 속성을 사용한다.
  • preload, prefetch 속성을 사용하여 리소스의 우선순위를 지정한다.

 

 

Reference

  • https://coffeeandcakeandnewjeong.tistory.com/34
  • https://beomy.github.io/tech/browser/critical-rendering-path/
  • https://beomy.github.io/tech/browser/preload-preconnect-prefetch/

공유하기

게시글 관리

구독하기Mok.js

'개발자 이야기' 카테고리의 다른 글

브라우저 렌더링  (0)2021.06.25

관련글 관련글 더보기

  • 브라우저 렌더링

댓글 0

댓글 접기 댓글 펼치기

이전 댓글 더보기

비밀글

등록

웹사이트 성능 최적화에는 어떤 방법이 있나요?

성능 향상을 위해 가장 효과적인 방법은 브라우저와 서버 사이의 통신을 최대한으로 줄이는 것입니다. 그러므로 다시 방문한 사용자에게 좀 더 빠른 응답 속도를 제공하려면 애플리케이션 캐시를 잘 활용해야 합니다. 캐시 설정시 몇가지 용어와 규칙 필요합니다.

React의 초기화면 느린 부분은 어떻게 해결해야해요?

React Rendering 속도 개선 해보기.
개선하기 전에 생각해 볼 것들..
먼저 생각해보자.
질문을 해결해보자.
REACT 초기 렌더링 개선하기.
시도1 : 코드 스플리팅.
시도 2 : 사용하지 않는 모듈 지우기.
시도 3 : 파일 사이즈 줄이기.
시도 4 : production sourcmap..