렌더링 성능 최적화 - Bottleneck code

2023. 5. 1. 14:04·프론트엔드/성능 최적화

Bottleneck 코드 최적화 1 - 작업양 줄이기

Bottleneck 코드 찾기

크롬 Performance를 활용해서 페이지가 렌더링될 때 각 컴포넌트 등의 실행시간을 체크해볼 수 있다.

이를 활용해 실행이 오래 걸리는 함수, 컴포넌트 등 Bottleneck 코드를 찾을 수 있다.

여기서 보면, Article 컴포넌트 mount 작업이 오래걸리는데, 아래에서 상세한 수행내역을 보면 removeSpecialCharacter 함수가 실행시간을 다 차지하고 있는 것을 확인할 수 있다.

이런식으로 Bottleneck코드를 찾을 수 있다.

Bottleneck 코드 분석

/*
 * 파라미터로 넘어온 문자열에서 일부 특수문자를 제거하는 함수
 * (Markdown으로 된 문자열의 특수문자를 제거하기 위함)
 * */
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
}

코드를 보면, 각 특수문자별로 for문을 돌고, 매개변수로 받은 str의 각 글자를 검사해서 해당 특수문자이면 제거하는 식으로 되어 있다.

불필요하게 for문을 2번 돌고 있다.

최적화하기

  1. 효율적으로 제거 - replace와 정규식을 활용한다면 가독성도 좋고, 실행시간도 적은 코드로 바꿔줄 수 있다.
  2. 작업양 줄이기 - summary에 보여지는 글자는 최대 300자이기 때문에 전체 str을 검사할 필요가 없다. 300자까지만 검사하도록 한다.
function removeSpecialCharacter(str) {
  return str.substring(0,300).replace(/[\#\_\*\~\&\;\!\[\]\`\>\n\=\-`]/g, '')
}

얼마나 빨라졌는지 보기

아까는 1초가 넘게 걸리던 작업이 28ms로 줄었다.

Lighthouse 점수도 이전 45점에서 52점으로 늘었다.

Total Blocing Time이 1초에서 70ms로 매우 줄었다.

Bottleneck 코드 최적화 2 - memoization

Bottleneck 코드 찾기

크롬 Performance로 오래 걸리는 코드를 찾아본다.

모달의 이미지를 기초로 배경색을 계산하는 getAverageColorOfImage가 매우 오래 걸리는 것을 알 수 있다.

Bottleneck 코드 분석

export function getAverageColorOfImage(imgElement) {
  const canvas = document.createElement('canvas');
  const context = canvas.getContext && canvas.getContext('2d');
  const averageColor = {
    r: 0,
    g: 0,
    b: 0,
  };

  if (!context) {
    return averageColor;
  }

  const width = (canvas.width =
    imgElement.naturalWidth || imgElement.offsetWidth || imgElement.width);
  const height = (canvas.height =
    imgElement.naturalHeight || imgElement.offsetHeight || imgElement.height);

  context.drawImage(imgElement, 0, 0);

  const imageData = context.getImageData(0, 0, width, height).data;
  const length = imageData.length;

  for (let i = 0; i < length; i += 4) {
    averageColor.r += imageData[i];
    averageColor.g += imageData[i + 1];
    averageColor.b += imageData[i + 2];
  }

  const count = length / 4;
  averageColor.r = ~~(averageColor.r / count); // ~~ => convert to int
  averageColor.g = ~~(averageColor.g / count);
  averageColor.b = ~~(averageColor.b / count);

  return averageColor;
}

계산 작업이 복잡하고 시간이 많이 걸린다.

최적화하기

메모이제이션

메모이제이션을 활용해서 이전에 했던 작업을 반복하지 않도록 하면 오버헤드를 줄일 수 있다.

const cache = {}
export function getAverageColorOfImage(imgElement) {
    if(cache.hasOwnProperty(imgElement.src)) {
        return cache[imgElement.src]
    }
    /// 생략

    cache[imgElement.src] = averageColor
    return averageColor
}

리액트 컴포넌트 내부의 메소드인 경우 useMemo를 활용할 수 있다.

따로 util 함수를 선언해서 사용하면 좋다. 클로져 활용해서 캐시 사용

// memoize.js
// 2번째 인자로 args 해싱하는 함수 넣어서 활용하면 object나 배열에도 활용할 수 있다.
function memoize(fn, hashFn) {
    const cache = {}
    return function(...args) {
        if(args.length !== 1) {
            return fn(...args)
        }

        const key = hashFn(args)

        if(cache.hasOwnProperty(key)) {
            return cache[key]
        }
        const result = fn(...args)
        cache[key] = result

        return result
    }
}
저작자표시

'프론트엔드 > 성능 최적화' 카테고리의 다른 글

렌더링 성능 최적화 - Layout Shift 피하기  (0) 2023.05.01
렌더링 성능 최적화 - 애니메이션  (0) 2023.05.01
로딩 성능 최적화 - 텍스트 압축, 불필요한 CSS 제거  (0) 2023.04.28
로딩 성능 최적화 - 캐시  (0) 2023.04.28
로딩 성능 최적화 - 폰트  (0) 2023.04.28
'프론트엔드/성능 최적화' 카테고리의 다른 글
  • 렌더링 성능 최적화 - Layout Shift 피하기
  • 렌더링 성능 최적화 - 애니메이션
  • 로딩 성능 최적화 - 텍스트 압축, 불필요한 CSS 제거
  • 로딩 성능 최적화 - 캐시
정현우12
정현우12
  • 정현우12
    정현우의 개발 블로그
    정현우12
  • 전체
    오늘
    어제
    • 분류 전체보기 (79)
      • 프론트엔드 (56)
        • JavaScript, TypeScript (12)
        • 스타일링 (1)
        • React (13)
        • Next.js (4)
        • 개발 환경 (9)
        • 테스트 (3)
        • 성능 최적화 (11)
        • 함수형 프로그래밍 (2)
        • 구조 (1)
      • 프로젝트 회고 (23)
        • 이미지편집기 개발 (7)
        • 엑셀 다운로드, 업로드 공통 모듈 개발 (4)
        • 사용자 매뉴얼 사이트 개발 (3)
        • 통계자동화 솔루션 개발 (1)
        • 엑셀 편집기 개발 (5)
        • API 플랫폼 (1)
        • 콜센터 솔루션 OB 캠페인 (1)
        • AI 스튜디오 (1)
      • 백엔드 (0)
  • 블로그 메뉴

    • 홈
    • 포트폴리오
    • 태그
  • 인기 글

  • 태그

    JavaScript
    React
    엑셀 에디터
    웹 성능 최적화
    사용자 매뉴얼 사이트
    Next.js
    회고
    memoization
    커스텀 훅
    TypeScript
    useReducer
    Github Actions
    React-boilerplate
    webpack
    렌더링 성능 최적화
    로딩 성능 최적화
    이미지 편집기
    엑셀
    라이브러리 선정
    frontend
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
정현우12
렌더링 성능 최적화 - Bottleneck code
상단으로

티스토리툴바