프론트엔드 성능최적화 - 렌더링 성능 최적화 | 개발새발

이렇게 삽질하다간 지구 끝까지 닿겠어

dev
프론트엔드 성능최적화 - 렌더링 성능 최적화

프론트엔드 성능최적화 - 렌더링 성능 최적화

프론트엔드 성능최적화 중 렌더링 성능 최적화에 대해 알아봅니다

2025.12.03

들어가기에 앞서

해당 글은 프론트엔드 성능최적화에 대한 기본 지식을 눌러 담은 글입니다. 글의 내용이 미비하거나 틀린 부분이 있을 수 있습니다. 해당 레포지토리의 이슈에 수정되어야 할 내용을 등록해주시면 감사히 글에 반영하겠습니다.

들어가며

앞선 글에서 렌더링 성능은 화면을 그릴 때의 성능을 말한다고 했습니다. 렌더링 성능을 개선하는 방법은 매우 다양하기에 서비스에 적절한 최적화 기법을 사용하기 위해서는 브라우저의 동작 원리나 프레임워크의 라이프 사이클 등의 기본 지식이 필요합니다. 해당 글에서는 앞서 설명했던 브라우저의 로딩 과정에 조금 더 덧붙인 글(리플로우와 리페인트)과 함께 크게 네가지의 렌더링 성능 개선 방법을 제시해보겠습니다.

리플로우와 리페인트

  • 렌더링

    • 브라우저의 로딩 과정파싱 -> 스타일 -> 레이아웃 -> 페인트 -> 합성의 과정을 거친다고 했습니다. 이 로딩 과정 중 스타일 이후의 과정을 렌더링 이라고 하는데 이 과정은 상황에 따라 반복적으로 일어날 수 있습니다.
  • 리플로우

    • 스타일 단계에서 발생하는 렌더 트리는 자바스크립트에 의해 DOM 이나 CSSOM 이 변경될 때 DOM 트리와 CSSOM 트리 재구성과 함께 렌더 트리도 재구성이 일어납니다. 이 때문에 레이아웃 단계 또한 재실행되며 이를 리플로우라고 합니다.
    • 리플로우 발생 CSS 속성: position,display, heightwidthfloat, lefttopfont-sizefont-weight, line-height , margin, padding, border
  • 리페인트

    • 레이아웃은 렌더 트리의 노드 하나하나의 위치와 크기를 계산한다고 했는데 만약 위치와 크기가 변경되지 않는 CSS 만 변경되게 되면 레이아웃 단계를 건너뛰게 됩니다. 페인트 단계부터 수행하며 이를 리페인트 라고 합니다.
    • 리페인트 발생 CSS 속성: background, background-image,background-position, background-color, border-radius, border-style,box-shadowvisibilitytext-decoration 등

레이아웃이 변경 되는 리플로우가 일어나게 되면 전체적인 렌더 트리의 노드의 위치와 크기를 계산하기 때문에 부하가 크나, 리페인트는 계산된 값을 사용하여 CSS의 속성만 적용하면 되기 때문에 부하가 적습니다. 부하가 큰 만큼 소요되는 시간도 크기 때문에 가급적 불필요한 리플로우가 일어나는 일을 지양하는 것이 렌더링 성능 최적화의 요점 중 하나라고 볼 수 있겠습니다.

렌더링 성능 최적화

웹페이지를 구현하기 위해서는 DOM과 CSS가 필요하나, 다양한 기능과 효과를 구현하기 위해서는 자바스크립트 코드를 많이 사용하기 때문에 해당 코드가 렌더링 성능에 어떤 영향을 주는지 아는 것이 필요합니다. 더불어 자바스크립트는 브라우저에서 단일 스레드로 동작하기 때문에 자바스크립트 코드의 실행 시간이 렌더링 시간과 직결합니다. 따라서, 자바스크립트 코드를 통해 일어나는 렌더링 성능을 최적화 할 수 있는 방법과 위에서 설명한 리플로우를 최대한 지양할 수 있는 방법에 대해 알아보겠습니다.

1. 병목 코드 최적화

병목이 발생하는 지점은 Performance 패널을 통해 확인할 수 있습니다. 해당 패널의 CPU 차트는 CPU가 어떤 작업에 리소스를 사용하고 있는지 보여주는데 이 때 변목이 발생하는 지점은 빨간색 선으로 표기됩니다. 해당 병목이 발생하는 지점을 확인하고 코드를 최적화 하면 병목 코드를 개선할 수 있습니다. 병목 코드를 최적화 하는 방법으로는 적용되는 코드마다 다르겠으나 메모이제이션 기법을 사용하거나 불필요한 반복문을 줄이거나 반복 횟수를 줄이는 등의 방법이 있겠습니다.

2. 사전 로딩

앞서 해당 코드가 필요해 지는 시점에 로드되어 실행되는데 이를 지연로딩이라고 설명한 바가 있습니다. 지연 로딩의 장점은 로드할 파일의 크기가 작아져 초기 로딩 속도와 자바스크립트의 실행 타이밍이 빨라지는 장점이 있습니다. 다만 이는 초기 화면 로딩 시에는 효과적일지 몰라도 모두 적용하기에는 상황에 따라 좋지 않은 방법일수도 있습니다.

이를테면 모달 기능을 구현할 시 지연 로딩을 적용하게 되면 모달을 띄우는 시점에 모달 코드를 새로 로드하고 완료 되는 시점에 모달을 띄울 수 있어 사용자가 느끼기에 모달 팝업이 오래 걸린다고 느낄 수 있습니다. 이 때 사전 로딩 기법을 이용하면 모달 팝업을 사용자가 느끼기에 지연된다고 느끼지 않게 효과적으로 팝업시킬 수 있습니다.

사전 로딩은 말 그대로 나중에 필요한 모듈을 미리 로드하는 방법입니다. 해당 모듈이 로드되기 위해 사용자의 행동이 예측된다면 해당 기법을 사용할 수 있겠습니다. 이를테면 모달을 팝업 시키기 위해 마우스를 모달을 팝업시키는 버튼 위에 올려놓았을 시 모듈을 로드한다면 모달이 팝업될 시에는 코드를 불러오는 시간과 준비 시간 등을 줄일 수 있어 효과적으로 모듈을 띄울 수 있습니다. 또한 사용자의 행동이 예측이 되는 상황이 아니라면 컴포넌트의 마운트 완료 후 사전 로딩을 하는 방법도 있겠습니다.

import { useState, useEffect } from "react"

function App() {
  const [showModal, setShowModal] = useState < boolean > false

  useEffect(() => {
    const component = import("./component/Modal")
  }, [])

  return <div className="App">...</div>
}

3. 애니메이션 최적화

위에서 이야기 했던 리플로우와 리페인트를 피하는 방법도 있습니다. 바로 transform이나 opacity와 같은 속성을 사용하는 방법입니다. 이런 속성을 사용하면 해당 요소를 별도의 레이어로 분리하고 작업을 GPU에 위임하여 처리함으로써 레이아웃 단계와 페인트 단계를 건너뛸 수 있습니다. 이를 하드웨어 가속이라고 합니다. 리플로우와 리페인트를 일으키는 width, height, color 등의 속성을 애니메이션에 사용하면 변할 때 마다 화면이 갱신되어 쟁크 현상이 일어날 수 있는데, transform 또는 opacity 속성을 이용하면 성능이 더 좋을 수 밖에 없습니다.

4. 레이아웃 이동 피하기

레이아웃 이동이란 화면상의 요소 변화로 레이아웃이 갑자기 밀리는 현상을 말합니다. 레이아웃 이동을 발생 시키는 원인은 다양한데 가장 큰 원인은 네가지 정도를 꼽을 수 있습니다.

  • 사이즈가 미리 정의되지 않은 요소
  • 동적으로 삽입된 콘텐츠
  • 웹 폰트(FOIT, FOUT)

결국 사이즈가 미리 정의 되지 않았다면 미리 사이즈를 지정하거나, 웹 폰트의 경우 FOUT 방식을 사용하거나 하는 방식으로 레이아웃 이동을 피할 수 있겠습니다. 또한 offsetHeightoffsetTop과 같은 계산된 값을 속성으로 읽을 때 강제로 동기 레이아웃을 하는 것을 피하는 것도 방법입니다.

5. 이 외

DOM을 변경하면 스타일 계산, 레이아웃, 페인트 과정이 모두 필요하며, 조작이나 스타일 변경을 하는 DOM이 상위에 있을수록 한 프레임에 드는 시간이 길어지므로 가능한 하위 노드의 DOM을 조작하거나 스타일을 변경, display: none 사용, DOM 깊이 최소화 등의 여러가지 방법으로 렌더링 성능을 최적화 하는 방법이 있습니다. 상황과 서비스 별로 특성에 맞게 성능 측정 도구를 참고하여 렌더링 성능을 최적화 하면 되겠습니다.


Reference

# FE-perfomance# perfomance