프론트엔드 첫걸음

성능 최적화와 유지보수를 위한 Javascript Pattern 본문

개발 공부/Javascript

성능 최적화와 유지보수를 위한 Javascript Pattern

차정 2024. 9. 1. 17:04

1. 단일 인스턴스 패턴 (Singleton Pattern)

    • 설명: 애플리케이션에서 특정 객체가 단일 인스턴스만 존재하도록 보장하는 패턴입니다. 예를 들어, 데이터베이스 연결 객체, 웹소켓 연결 객체 등이 여기에 해당합니다.
    • 예시
class Singleton {
  constructor() {
    if (!Singleton.instance) {
      Singleton.instance = this;
    }
    return Singleton.instance;
  }

  // Other methods here...
}

const instance = new Singleton();
Object.freeze(instance); // 객체를 수정할 수 없게 만듦
export default instance;
  • 활용: 데이터베이스 연결, 캐시 객체, 설정 관리자 등 애플리케이션에서 단일 인스턴스만 존재해야 하는 객체에 사용됩니다.

2. 초기화 플래그 (Initialization Flag)

    • 설명: 특정 작업이 한 번만 실행되도록 보장하기 위해 플래그 변수를 사용하는 패턴입니다. 주로 비동기 작업이나 이벤트 핸들러에서 사용됩니다.
    • 예시:
  let isInitialized = false;

function initialize() {
  if (!isInitialized) {
    // 초기화 작업 실행
    isInitialized = true;
  }
}

// 이 함수를 여러 번 호출해도 초기화 작업은 한 번만 실행됨
initialize();
initialize();

  

 

- 초기화 패턴을 사용하여 A,B 둘다 완료되었을때에만 C 실행하게 하기 

let isALoaded = false;
let isBLoaded = false;

function loadA() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("A 로딩 완료");
      isALoaded = true;
      checkIfReadyToExecuteC();
      resolve();
    }, 1000); // 1초 후에 로딩 완료
  });
}

function loadB() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("B 로딩 완료");
      isBLoaded = true;
      checkIfReadyToExecuteC();
      resolve();
    }, 2000); // 2초 후에 로딩 완료
  });
}

function checkIfReadyToExecuteC() {
  if (isALoaded && isBLoaded) {
    executeC();
  }
}

function executeC() {
  console.log("C 실행됨");
}

// 초기화 함수에서 A와 B를 로드
function initialize() {
  loadA();
  loadB();
}

initialize();
  • 활용: 초기화 작업, 이벤트 리스너 설정, 외부 라이브러리 초기화 등에 사용됩니다.

3. Memoization (메모이제이션)

    • 설명: 함수의 결과를 캐시하여 동일한 입력으로 반복 계산을 피하는 패턴입니다. 복잡한 계산이나 API 호출 결과를 캐시할 때 유용합니다.
    • 예시:
  function memoize(fn) {
  const cache = {};
  return function (...args) {
    const key = JSON.stringify(args);
    if (!cache[key]) {
      cache[key] = fn(...args);
    }
    return cache[key];
  };
}

const expensiveFunction = memoize((num) => {
  console.log("Expensive calculation...");
  return num * num;
});

console.log(expensiveFunction(5)); // 비용이 많이 드는 계산 -> 캐시에 저장
console.log(expensiveFunction(5)); // 비용이 많이 드는 계산 2번 안하고, 캐시된 결과 반환
  • 활용: 비용이 큰 함수의 결과를 캐시하여 성능을 최적화할 때 사용됩니다.

4. 모듈 패턴 (Module Pattern)

    • 설명: 전역 네임스페이스 오염을 피하면서, 필요한 변수와 함수를 모듈화하여 관리하는 패턴입니다. ES6 이후에는 import와 export를 사용하여 모듈 패턴을 구현합니다.
    • 예시:
  const myModule = (() => {
  let privateVar = "I am private";

  function privateFunction() {
    console.log(privateVar);
  }

  return {
    publicMethod: () => {
      privateFunction();
    },
  };
})();

myModule.publicMethod(); // I am private

  
  • 활용: 전역 변수의 사용을 피하면서 특정 기능을 모듈화하고, 필요에 따라 외부에 노출할 때 사용됩니다.

5. 이벤트 딱 한 번 실행 (Event Once)

    • 설명: 이벤트 리스너를 한 번만 실행하도록 설정하는 패턴입니다. 이벤트가 발생한 후 리스너가 자동으로 제거되도록 합니다.
    • 예시:
  const button = document.querySelector("button");

function handleClick() {
  console.log("Button clicked");
}

button.addEventListener("click", handleClick, { once: true });

  
  • 활용: 특정 이벤트가 한 번만 실행되도록 보장해야 할 때 사용됩니다.

6. Debounce (디바운스) & Throttle (스로틀)

    • 설명: debounce는 함수 호출을 특정 시간 동안 지연시켜 마지막 호출만 실행되도록 하며, throttle은 일정한 간격으로 함수 호출을 제한합니다.
    • 예시:
  function debounce(fn, delay) {
  let timeoutId;
  return function (...args) {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }
    timeoutId = setTimeout(() => {
      fn(...args);
    }, delay);
  };
}

function throttle(fn, interval) {
  let lastTime = 0;
  return function (...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      fn(...args);
      lastTime = now;
    }
  };
}

const debouncedFunction = debounce(() => {
  console.log("Debounced function called");
}, 300);

const throttledFunction = throttle(() => {
  console.log("Throttled function called");
}, 300);

  
  • 활용: 스크롤, 리사이즈, 키 입력 등의 이벤트 핸들러에서 과도한 호출을 방지하여 성능을 최적화할 때 사용됩니다.

7. 캐싱 패턴

    • 설명: 계산된 결과나 데이터를 캐시하여 반복적인 호출에서 비용을 줄이는 패턴입니다. API 호출이나 데이터베이스 조회 결과를 캐싱할 때 유용합니다.
    • 예시:
  const cache = new Map();

async function fetchData(url) {
  if (cache.has(url)) {
    return cache.get(url);
  } else {
    const response = await fetch(url);
    const data = await response.json();
    cache.set(url, data);
    return data;
  }
}

  
  • 활용: 외부 API 호출, 데이터베이스 조회 결과, 또는 복잡한 계산의 결과를 캐싱하여 성능을 개선할 때 사용됩니다.

8. Lazy Initialization (지연 초기화)

    • 설명: 객체나 리소스의 초기화가 실제로 필요할 때까지 지연시키는 패턴입니다. 리소스가 무조건 초기화될 필요가 없을 때 사용됩니다.
    • 예시:
  class Resource {
  constructor() {
    this.data = null;
  }

  initialize() {
    if (!this.data) {
      this.data = "Expensive Data";
    }
    return this.data;
  }
}

const resource = new Resource();
console.log(resource.initialize()); // "Expensive Data"

  
  • 활용: 비싼 초기화 작업이 나중에 필요해질 때까지 지연시켜 성능을 최적화할 때 사용됩니다.