병목 함수에 memoization 적용
병목함수 memoiztion 적용은 pure function일 때만 가능하다.
const cache = {};
export function getAverageColorOfImage(imgElement) {
if (cache.hasOwnProperty(imgElement)) {
console.log('cache has the key', cache);
return cache[imgElement];
}
console.log('cache dont have the key', cache);
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);
cache[imgElement] = averageColor;
return averageColor;
}
모듈 바깥에 cache 객체를 두고 캐시가 있을 경우 기록을 return, 그렇지 않을 경우 마지막에 캐시를 저장해둔다.
- 다른 이미지에 대해서도 캐시가 저장됐다고 뜨는 문제
object HTMLImageElement 값으로 input이 들어가서 같은 키로 인식됐다.
src url을 키로 활용하자.
const cache = {};
export function getAverageColorOfImage(imgElement) {
if (cache.hasOwnProperty(imgElement.src)) {
console.log('cache has the key', imgElement.src);
return cache[imgElement.src];
}
console.log('cache dont have the key', imgElement.src);
...
cache[imgElement.src] = averageColor;
return averageColor;
}
정상 작동을 확인할 수 있다.
팩토리 패턴 적용
캐시를 사용해야하는 대상이 많을 경우 일일이 위와 같은 방식으로 객체를 따로 설정하기 번거롭고 관리가 용이하지 못하다.
팩토리 패턴으로 설계해보자.
// memoize.js
function memoize(fn) {
const cache = {};
return function (...args) {
if(args.length !== 1){
return fn(...args);
}
if (cache.hasOwnProperty(args)) {
return cache[args];
}
const result = fn(...args);
cache[args] = result;
return result;
};
}
위와 같은 예시의 함수로 기존 함수를 wrapping 해주면 캐시를 이용하는 함수로 쉽게 만들어줄 수 있다.
memoization의 기회비용
input 값이 매번 달라지는 함수 등은 이런 memoization을 사용할 경우 오히려 메모리의 낭비만 일으킬 수 있다.
같은 input이 자주 쓰이거나, 함수의 작동 자체가 복잡한 경우 이용하면 좋다.
정리
Layout Shift 피하기
→ 이미지 지연(lazy) 로딩
→ useSelector 렌더링 문제 해결
→ Redux Reselect를 통한 렌더링 최적화
→ 병목 함수에 memoization 적용
'web' 카테고리의 다른 글
[React Test] 간단히 만들어보기 - ESLint Plugins, FireEvent 등 (0) | 2022.08.13 |
---|---|
[React Test] 리액트 테스트에 대해서 - RTL, Jest, 쿼리함수 (0) | 2022.08.10 |
[React 최적화] 실습 4. 이미지 갤러리 페이지(2) - useSelect 렌더링 문제, Redux reselect (0) | 2022.08.04 |
[React 최적화] 실습 4. 이미지 갤러리 페이지(1) - Layout Shift, react-lazyload (0) | 2022.08.03 |
[React 최적화] 실습 3. 일반 홈페이지(3) - 캐시, css 최적화 (0) | 2022.08.01 |