Front-End/성능개선

[웹 성능 최적화] - 이미지 사이즈 조절, Bottle neck 제거 (1/3)

딸기케잌🍓 2023. 2. 6. 14:16

다음은 인프런에서 유동균님의 프론트엔드 개발자를 위한, 실전 웹 성능 최적화(feat.React)- Part. 1을 완강하며 공부한 내용입니다.

 

웹 성능 최적화(=로딩 성능 최적화 & 렌더링 성능 최적화)


웹 성능 최적화는 크게 로딩 성능 최적화와 렌더링 성능 최적화로 구분할 수 있습니다.

로딩 성능 최적화클라이언트가 서버로부터 웹 페이지를 그리는데 필요한 리소스들을 다운 받는 로딩 시점에서의 성능을 최적화 하는 것입니다. 로딩 성능 최적화에는 이미지 사이즈 최적화, Code Splitting, 텍스트 압축 등이 있습니다. 

렌더링 성능 최적화는 클라이언트 단의 브라우저에서 화면을 그릴 때의 성능을 최적화 하는 것을 말합니다. 렌더링 성능 최적화에는 BottleNeck 코드 최적화 등이 있습니다.

 

로딩 성능 최적화

이미지 사이즈 최적화

- 이미지의 크기가 너무 크면 부하를 줄 수 있고 너무 작으면 저화질일 수 있습니다. 적절한 이미지 사이즈로 최적화 하는것을 말합니다.

 

code splitting

- 코드 스플릿이란 불필요한 코드 또는 중복되는 코드가 없이 적절한 사이즈의 코드가 적절한 타이밍에 로드 될 수 있도록 하는 것인데, 코드를 어떻게 언제 분할해야 효울적인지에 대해 최적화 하는 과정입니다.

 

텍스트 압축

- javascript, css, html 리소스를 서버로부터 다운받기 전에 압축하여 로딩 성능을 최적화하는 방법입니다. 보통 2KB 이상인 항목에 대해서 압축을 수행합니다.

 

렌더링 성능 최적화

BottleNeck 코드 최적화

-병목 현상을 일으키는 코드를 어떻게 찾아내고 어떻게 해결 할 수 있는지에 대한 내용입니다.

 

 

본인이 만든 웹사이트 최적화를 해볼까요!?


개발자 도구의 Lighthouse 툴을 이용하여 페이지 검사를 해봅니다.

 

잠시 후 아래와 같이 분석 결과를 알려줍니다. Performance 점수가 100점 만점에 21점인 것을 알 수 있습니다.

 

스크롤을 조금 더 내려보면 성능 저해 원인과 그것을 해결 할 수 있는 가이드인 OPPORTUNITIES와 DIAGNOSTICS 항목이 보입니다. OPPORTUNITIES는 로딩 성능 관점에서의 가이드이고 DIAGNOSTICS는 렌더링 관점에서의 가이드입니다. 

 

 

이미지 사이즈 줄여서 최적화하기

다음은 이미지 사이즈를 더 줄이라는 opportunities입니다.

저 이미지들을 요소 검사로 살펴보니 Rendered size(화면에 렌더되는 이미지의 영역)은 120 x 120 px인데 Intrinsic size(실제 이미지의 크기)는 1200 x 1200 px 입니다. 약 100배 정도가 차이나고 있네요.

 

이미지를 줄여줬야 겠는데 표시해야 하는 크기 대비 2배 정도의 사이즈로 렌더링하면 좋습니다.

많이 쓰이는 레티나 디스플레이는 같은 공간에 2배 정도 더 많은 픽셀을 표현할 수 있기 때문에 

렌더링 해야 하는 크기가 120px  * 120px 이라면 240px * 240px로 이미지 크기를 지정하는 것이죠.

 

만약 내 로컬서버에서 이미지 크기를 컨트롤하는 것이 아니고, 서버에서 api를 이용하여 이미지를 받아오는 경우라면 imgix와 같은 image CDN을 이용하면 됩니다.

 

image CDN(=image processing CDN)이란?

CDN은 Contents Delivery Network의 약자로 물리적 거리의 한계를 극복하기 위해 클라이언트와 가까운 곳에 컨텐츠 서버를 두는 기술입니다.

image CDN은 CDN과 같이 컨텐츠를 미리 클라이언트와 가까운 서버에 보관하고 있으면서 이미지 사이즈나 이미지 포맷을 변경 할 수 있게 해줍니다.

예를 들어 다음과 같이 image CDN 서버를 이용하여 클라이언트가 원하는 이미지를 받아 올 수 있습니다.

 http://cdn.image.com?src=[img src]&width=200&height=100

 

 

병목현상(bottle neck)을 일으키는 코드 탐색과 최적화하기

Reduce JavaScript execution time 을 보면 js코드를 실행하는데 꽤 걸리고 있다는 것을 알 수 있습니다.

 

병목 현상을 파악하기 위해 개발자 도구의 Performance 탭에서 살펴보겠습니다.

 

리로드 버튼을 클릭하여 성능 분석을 마치면 다음과 같은 그래프 결과가 나옵니다.

 

 

확대해서 오른쪽으로 타임라인을 이동하며 가다보면 Network 그래프에서 /articles로 요청한 것의 콜백이 꽤 긴 것을 확인할 수 있습니다.

같은 타임라인으로 아래쪽을 더 살펴보면 Timings 에서도 Article 컴포넌트가 길게 차지하고 있고,

Main 에서도 Article 컴포넌트의 removeSpecialCharacter 함수가 대부분을 차지하고 있는 것을 확인할 수 있습니다.

removeSpecialCharacter함수가 잘려서 마치 여러번 수행된 것처럼 보이는데 Article컴포넌트에는 removeSpecialCharacter함수가 한 번만 실행된 상황입니다. 이는 GC에 의해 메모리를 비워주는 과정 때문에 차트가 끊겨져서 표현이 되었습니다.

자, 그럼 우리는 removeSpecialCharacter 함수를 조금 더 효율적으로 수정해주면 됩니다.

removeSpecialCharacter 메서드는 이중 포문으로 한눈에 봐도 리팩토링이 필요한 것을 알 수 있습니다.

function removeSpecialCharacter(str) {
  const removeCharacters = ['#', '_', '*', '~', '&', ';', '!', '[', ']', '`', '>', '\n', '=', '-']
  let _str = str
  let i = 0,
    j = 0

  for (i = 0; i < removeCharacters.length; i++) {
    j = 0
    while (j < _str.length) {
      if (_str[j] === removeCharacters[i]) {
        _str = _str.substring(0, j).concat(_str.substring(j + 1))
        continue
      }
      j++
    }
  }

  return _str
}

다음과 같이 정규식과 javascript의 replace 함수를 사용해서 수정했습니다.

function removeSpecialCharacter(str) {
  let _str = str.substring(0, 300); //대상 스트링 길이 줄이기(300자 이후에는 화면에 렌더링 되지 않음)
  _str = _str.replace(/[\#\_\*\~\&\;\~\[\]\`\n\=\-]/g, ""); //정규식과 replace로 이중포문 개선

  return _str;
}

 

Performance 탭의 리로드 버튼을 다시 클릭합니다.

타임라인에 3494ms, 3994ms 이 보이도록 위의 타임라인과 똑같이 확대해보니 Network 차트에서 /articles로 요청,응답,콜백을 담은 그래프가 아주 짧아진 것을 확인할 수 있습니다.

 

Main 차트 부분을 아~~주아주 확대해보면 Article 컴포넌트의 removeSpecialCharacter함수를 찾을 수 있었습니다.

아까 여러군데 계속 있었던과는 다르게 깔끔하게 한 번만 보이고 있습니다. YEAH~!!!

 

 

정리가 너무 힘드네요...ㅠㅠ하나하나 캡쳐하면서 다시 복습하게 되어 좋지만 너무 오래걸려서 훌쩍..ㅜ 다시 돌아오겠습니다...

(하기싫어서 여기서 마치는거아님 주의!!!)