렌더링 성능

사용자는 사이트와 앱이 제대로 실행되지 않으면 이를 알아차리므로 렌더링 성능을 최적화하는 것이 중요합니다.

오늘날의 웹 사용자는 방문하는 페이지가 상호작용적이고 원활할 것으로 기대하며, 여기에 점점 더 많은 시간과 노력을 기울여야 합니다. 페이지는 빠르게 로드될 뿐만 아니라 전체 수명 주기 동안 사용자 입력에 빠르게 응답해야 합니다. 실제로 사용자 환경의 이 측면은 다음 페인트에 대한 상호작용 (INP) 측정항목이 측정하는 것과 정확히 일치합니다. INP가 양호하다는 것은 페이지가 사용자의 요구에 일관되고 안정적으로 반응했다는 의미입니다.

페이지가 빠르게 느껴지도록 하는 주요 구성요소는 사용자 상호작용에 대한 응답으로 실행하는 JavaScript의 양과 관련이 있지만, 사용자가 기대하는 것은 사용자 인터페이스의 시각적 변화입니다. 사용자 인터페이스의 시각적 변경사항은 여러 유형의 작업(종종 렌더링이라고 통칭함)의 결과이며, 사용자 환경이 빠르고 안정적으로 느껴지도록 이 작업은 최대한 빨리 이루어져야 합니다.

사용자 상호작용에 빠르게 반응하는 페이지를 작성하려면 브라우저에서 HTML, JavaScript, CSS를 처리하는 방식을 이해하고 작성하는 코드와 포함하는 다른 서드 파티 코드가 최대한 효율적으로 실행되도록 해야 합니다.

기기 화면 재생 빈도에 관한 참고사항

휴대전화에서 웹사이트와 상호작용하는 사용자
디스플레이의 화면 재생 빈도는 사용자 입력에 반응하는 웹사이트를 빌드할 때 중요한 고려사항입니다.

오늘날 대부분의 기기는 화면을 초당 60회 새로고침합니다. 각 새로고침은 표시되는 시각적 출력을 생성하며 일반적으로 프레임이라고 합니다. 다음 동영상에서는 프레임 개념을 보여줍니다.

Chrome DevTools의 성능 패널에 표시된 프레임 커서가 상단 근처의 슬라이드 위를 스크러빙하면 모바일 탐색 메뉴가 '열기' 상태로 애니메이션화되면서 각 프레임의 확대된 표현이 도움말 내에 표시됩니다.

기기의 화면은 항상 일정한 속도로 새로고침되지만 기기에서 실행되는 애플리케이션이 항상 새로고침 빈도에 맞게 충분한 프레임을 생성할 수 있는 것은 아닙니다. 예를 들어 애니메이션이나 전환이 실행 중인 경우 브라우저는 기기의 화면 재생 빈도와 일치하여 화면이 새로고침될 때마다 하나의 프레임을 생성해야 합니다.

일반적인 디스플레이는 초당 60회 새로고침되므로, 간단히 계산해 보면 브라우저가 각 프레임을 생성하는 데 16.66밀리초가 걸린다는 것을 알 수 있습니다. 하지만 실제로는 브라우저에 각 프레임에 대한 자체 오버헤드가 있으므로 모든 작업을 10밀리초 이내에 완료해야 합니다. 이 예산을 충족하지 못하면 프레임 속도가 떨어지고 페이지 콘텐츠가 화면에서 흔들립니다. 이러한 현상을 버벅거림이라고 합니다.

하지만 목표는 하려는 작업 유형에 따라 달라집니다. 10밀리초 기준점을 충족하는 것은 애니메이션에 매우 중요합니다. 애니메이션에서는 화면의 객체가 두 지점 사이의 일련의 프레임에 걸쳐 보간됩니다. 사용자 인터페이스의 불연속적인 변경, 즉 중간에 모션 없이 한 상태에서 다른 상태로 진행되는 변경의 경우 사용자에게 즉각적으로 느껴지는 기간 내에 이러한 변경을 달성하는 것이 좋습니다. 이러한 경우 100밀리초가 자주 인용되는 수치이지만, INP 측정항목의 '좋음' 임곗값은 다양한 기능을 갖춘 더 광범위한 기기를 수용하기 위해 200밀리초 이하입니다.

목표가 무엇이든(버벅거림을 방지하기 위해 애니메이션에 필요한 많은 프레임을 생성하거나, 사용자 인터페이스에서 가능한 한 빨리 개별적인 시각적 변화를 생성하는 것) 브라우저의 픽셀 파이프라인이 작동하는 방식을 이해하는 것은 작업에 필수적입니다.

픽셀 파이프라인

웹 개발자로서 알아야 하고 유의해야 할 5가지 주요 영역이 있습니다. 이 다섯 가지 영역은 개발자가 가장 많이 제어할 수 있는 영역이며, 각 영역은 픽셀-화면 파이프라인의 핵심 지점을 나타냅니다.

JavaScript, 스타일, 레이아웃, 페인트, 합성의 5단계로 구성된 전체 픽셀 파이프라인
전체 픽셀 파이프라인을 보여주는 그림
  • JavaScript: JavaScript는 일반적으로 사용자 인터페이스의 시각적 변경을 초래하는 작업을 처리하는 데 사용됩니다. 예를 들어 jQuery의 animate 함수, 데이터 세트 정렬, 페이지에 DOM 요소 추가 등이 있습니다. 하지만 시각적 변경사항을 트리거하는 데 JavaScript가 반드시 필요한 것은 아닙니다. CSS 애니메이션, CSS 전환, Web Animations API를 사용하면 페이지 콘텐츠에 애니메이션을 적용할 수 있습니다.
  • 스타일 계산: 일치하는 선택자를 기반으로 어떤 HTML 요소에 어떤 CSS 규칙을 적용할지 파악하는 프로세스입니다. 예를 들어 .headline는 headline 클래스를 포함하는 class 속성 값이 있는 모든 HTML 요소에 적용되는 CSS 선택자의 예입니다. 여기에서 규칙이 알려지면 규칙이 적용되고 각 요소의 최종 스타일이 계산됩니다.
  • 레이아웃: 브라우저가 요소에 적용되는 규칙을 알게 되면 페이지의 도형(예: 요소가 차지하는 공간과 화면에 표시되는 위치)을 계산하기 시작할 수 있습니다. 웹의 레이아웃 모델은 한 요소가 다른 요소에 영향을 줄 수 있음을 의미합니다. 예를 들어 <body> 요소의 너비는 일반적으로 트리 전체에서 하위 요소의 크기에 영향을 미치므로 브라우저에서 이 프로세스가 상당히 복잡할 수 있습니다.
  • 페인트: 페인트는 픽셀을 채우는 프로세스입니다. 페이지에서 레이아웃이 계산된 후 텍스트, 색상, 이미지, 테두리, 그림자, 기본적으로 요소의 모든 시각적 측면을 그리는 작업이 포함됩니다. 그리기는 일반적으로 레이어라고 하는 여러 표면에서 이루어집니다.
  • 합성: 페이지의 일부가 여러 레이어에 그려질 수 있으므로 페이지가 예상대로 렌더링되도록 올바른 순서로 화면에 적용해야 합니다. 이는 다른 요소와 겹치는 요소에 특히 중요합니다. 실수가 발생하면 한 요소가 다른 요소 위에 잘못 표시될 수 있기 때문입니다.

픽셀 파이프라인의 각 부분은 애니메이션에 버벅거림을 유발하거나 사용자 인터페이스의 개별적인 시각적 변경사항에 대해서도 프레임 그리기를 지연시킬 수 있습니다. 따라서 코드가 트리거하는 파이프라인 부분을 정확하게 이해하고, 렌더링하는 데 필요한 픽셀 파이프라인 부분으로만 변경사항을 제한할 수 있는지 조사하는 것이 중요합니다.

'페인트'와 함께 '래스터화'라는 용어를 들어보셨을 것입니다. 그리기 작업은 실제로 다음 두 가지 작업으로 구성되기 때문입니다.

  1. 그리기 호출 목록 만들기
  2. 픽셀을 채우는 중입니다.

후자를 '래스터화'라고 하므로 DevTools에서 페인트 레코드를 볼 때마다 래스터화를 포함하는 것으로 생각해야 합니다. 일부 아키텍처에서는 그리기 호출 목록 생성과 래스터화가 서로 다른 스레드에서 실행되지만, 이는 개발자가 제어할 수 없습니다.

모든 프레임에서 파이프라인의 모든 부분을 건드릴 필요는 없습니다. 실제로 JavaScript, CSS 또는 Web Animations API를 사용하여 시각적 변경을 수행할 때 파이프라인이 특정 프레임에 대해 일반적으로 실행되는 방식은 세 가지가 있습니다.

1. JS/CSS > 스타일 > 레이아웃 > 페인트 > 합성

전체 픽셀 파이프라인(생략된 단계 없음)

너비, 높이 또는 위치와 같은 요소의 도형을 변경하는 속성 (예: left 또는 top CSS 속성)과 같은 '레이아웃' 속성을 변경하면 브라우저에서 다른 모든 요소를 확인하고 페이지를 '리플로우'해야 합니다. 영향을 받는 영역은 다시 페인팅해야 하며, 최종 페인팅된 요소는 다시 합성해야 합니다.

2. JS/CSS > 스타일 > 페인트 > 합성

레이아웃 단계가 생략된 픽셀 파이프라인

CSS에서 요소의 '페인트 전용' 속성(예: background-image, color, box-shadow과 같은 속성)을 변경한 경우 페이지에 시각적 업데이트를 커밋하는 데 레이아웃 단계가 필요하지 않습니다. 가능한 경우 레이아웃 단계를 생략하면 다음 프레임을 생성하는 데 상당한 지연 시간을 유발할 수 있는 비용이 많이 드는 레이아웃 작업을 방지할 수 있습니다.

3. JS/CSS > 스타일 > 합성

레이아웃 및 페인트 단계가 생략된 픽셀 파이프라인

레이아웃이나 페인트가 필요하지 않은 속성을 변경하면 브라우저가 합성 단계로 바로 이동할 수 있습니다. 이는 애니메이션이나 스크롤과 같은 페이지 수명 주기의 고압 지점에 대한 픽셀 파이프라인을 통해 가장 저렴하고 바람직한 경로입니다. 흥미로운 사실: Chromium은 페이지 스크롤을 최적화하여 가능한 경우 컴포지터 스레드에서만 발생하도록 합니다. 즉, 페이지가 응답하지 않더라도 페이지를 스크롤하여 이전에 화면에 그려진 부분을 볼 수 있습니다.

웹 성능은 작업을 피하는 기술이며, 필요한 작업의 효율성을 최대한 높입니다. 대부분의 경우 브라우저와 함께 작동하는 것이지 브라우저와 반대로 작동하는 것이 아닙니다. 이전에 파이프라인에서 보여준 작업은 계산 비용 측면에서 다르다는 점을 기억해야 합니다. 일부 작업은 본질적으로 다른 작업보다 비용이 더 많이 듭니다.

파이프라인의 다양한 부분을 살펴보겠습니다. 일반적인 문제와 이를 진단하고 해결하는 방법을 살펴보겠습니다.

브라우저 렌더링 최적화

Udacity 과정 스크린샷

성능은 사용자에게 중요하며, 우수한 사용자 환경을 구축하려면 웹 개발자는 사용자 상호작용에 빠르게 반응하고 원활하게 렌더링하는 웹사이트를 빌드해야 합니다. 성능 전문가 Paul Lewis가 버벅거림을 없애고 초당 60프레임 성능을 유지하는 웹 앱을 만드는 방법을 알려드립니다. 이 과정을 마치면 앱을 프로파일링하고 최적화되지 않은 렌더링 성능의 원인을 파악하는 데 필요한 도구를 사용할 수 있게 됩니다. 또한 브라우저의 렌더링 파이프라인을 살펴보고 사용자가 사용하기에 즐거운 빠른 웹사이트를 더 쉽게 빌드할 수 있는 패턴을 알아봅니다.

이 과정은 Udacity를 통해 제공되는 무료 과정이며 언제든지 수강할 수 있습니다.