본문 바로가기
프로젝트/Fullstack

[Svelte] 효율적인 메모리 관리방법

by bingual 2024. 11. 29.
반응형

소개

 

 

GitHub - bingual/sveltekit5: svelte5, 기타 라이브러리 테스트

svelte5, 기타 라이브러리 테스트. Contribute to bingual/sveltekit5 development by creating an account on GitHub.

github.com

 

해당 프로젝트는 최신 `Svelte 5`와 `SvelteKit`을 기반으로 구축된 프로젝트로, 클린 코드와 유지 보수를 중점적으로 고려한 웹 애플리케이션입니다.

 

성능 최적화, 재사용 가능한 컴포넌트 설계, 모듈화, 메모리 누수 관리, 중복 제거, 테스트 코드 작성을 목표로 하여 효율적인 개발 환경을 구성하는데 초점을 맞춘 기능 테스트가 목표입니다.

 

`Svelte 5` 는 2024년 10월 19일 정식으로 릴리즈 되었습니다.

 

한국에서는 `React`, `Vue`, `Next`와는 다르게 인지도가 낮지만 빠르고 편리하며 프레임워크 내에서 자체적으로 제공하는 기능이 많아 개발 경험이 좋기에 해외에서는 핫한 프레임워크 중 하나입니다.

 

현재 사용하는 `Svelte 5` 및 기타 라이브러리들은 베타 버전도 포함하고 있기에 버그가 있을 수 있습니다.

앞으로 연재될 Svelte 5 포스팅들은 단순히 기능을 구현하는 것만이 아니라 어떻게 해야 효율적으로 기능들을 구현하고 사용 및 관리하는지에 대해 설명을 진행할 예정입니다.

Sveltekit, Prisma, Tailwind, Auth 등등 해당 프로젝트에 사용되는 라이브러리에 대한 설명은 없으므로 공식문서를 참고 바랍니다.

프로젝트 구조

prisma/               # Prisma 관련 설정 및 파일 폴더
e2e/                  # E2E 테스트 코드 폴더
src/                  # 소스 코드 루트 폴더
├── lib/              # 재사용 가능한 라이브러리 코드 폴더
│   ├── auth.ts       # Oauth 코드
│   ├── prisma.ts     # Prisma 인스턴스 코드
│   ├── supabaseClient.ts  # Supabase 관련 코드
│   ├── utils/        # 유틸리티 코드 폴더
│   └── components/  # Svelte 컴포넌트 폴더
├── routes/          # SvelteKit 라우팅 폴더
└── tests/           # 유닛 테스트 코드 폴더

명시되지 않은 코드 구조가 있을 수 있습니다.

 

 

내용 요약

설명은 간단하게 진행되니 자세한 설명은 참조하는 링크를 참고해 주세요.

  • `unsubscribe`을 사용해야 되는 이유와 방법
  • `$effect`의 클린업 함수를 이용해 언마운트 시 메모리 해제

 

 

unsubscribe을 사용해야 되는 이유와 방법

프로그래밍에서 `읽기`, `쓰기` 작업을 해야하는 경우 조심해야 하는 부분이 있는데요. 그것이 `메모리 릭`입니다.
어떤 작업에서든 메모리가 할당된 후 적절히 해제되지 않을 경우 발생할 수 있습니다.

 

`svelte`의 `subscribe`은 구독을 함으로써 특정 스토어의 값이 변화를 감지할 수 있습니다. 

` subscribe`은 상태가 변경될 때마다 콜백 함수를 실행하므로 더 이상 사용하지 않게 될 때 작업을 해제해야 할 필요성이 있죠.



`variables.ts`

export const useLoadMore = () => {
  const key = 'take';
  const interval = 20;
  const url = get(page).url;
  const currentTake = writable(interval);

  const unsubscribe = page.subscribe((value) => {
    const url = value.url;
    currentTake.set(Number(url.searchParams.get(key)) || interval);
  });

  const loadMoreData = async () => {
    if (!browser) return;

    currentTake.update((value) => value + interval);

    url.searchParams.set(key, String(get(currentTake)));
    await goto(url.toString(), { replaceState: true, noScroll: true });
  };

  onDestroy(() => unsubscribe());

  return {
    interval,
    currentTake,
    loadMoreData,
  };
};


더 보기를 관리하는 함수입니다.

https://svelte.dev/docs/kit/@sveltejs-kit#Page

`page`는 `sveltekit`에 존재하는 페이지를 관리하는 전역 스토어 중 하나입니다. 


`unsubscrib` 함수는 보면  `page.url.searchParams`가 변경될 때마다 호출되고 지정된 `key`를  `searchParams`에서 가져와서 `currentTake`에 값을 할당하고 있습니다.

보통 더 보기 버튼은 페이징이 필요한 특정 페이지나 컴포넌트가 아니라면 사용할 이유가 없어지죠. 그래서 언마운트 되었을 때 구독을 취소할 필요성이 있습니다.

`setInterval`과 마찬가지로 선언한 `subscrib` 함수 또한 클린업 함수이며 호출 시 메모리를 해제할 수 있습니다. 

https://svelte.dev/docs/svelte/lifecycle-hooks#onDestroy
`onDestory` 함수는 `sveltekit`에서 라이프 사이클을 관리하는 함수입니다.
클라이언트단에서만 사용가능하며 `ts`파일에서 사용했을 경우 호출되는 부모가 `svelte` 확장이어야만 합니다.

이 함수를 사용하게 되면 언마운트 됐을 때 `unsubscrib`을 호출하여 메모리를 해제할 수 있겠습니다.


 

$effect의 클린업 함수를 이용한 방법

 

`SetImage.svelte`

$effect(() => {
  modalStatus = imageModalUi.isOpen;

  if (selectedFiles) {
    const imageValidation = imageFilesSchema.safeParse(Array.from(selectedFiles));

    if (imageValidation.success) {
      isValid = true;
      filePreviews = selectedFiles
        ? map(Array.from(selectedFiles), (file) => ({
            src: URL.createObjectURL(file),
            alt: file.name,
          }))
        : [];
    } else {
      isValid = false;
      errors = imageValidation.error?.errors
        ? map(imageValidation.error.errors, (err) => ({
            field: err.path[0],
            message: err.message,
          }))
        : [];
    }
  }

   return () => {
     if (!isEmpty(filePreviews)) {
       forEach(filePreviews, (file) => URL.revokeObjectURL(file.src));
       filePreviews = [];
     }
   };
});



이 코드는 `$effect`에서 임시 이미지 `blob:URL`을 생성하고 있습니다. 임시로 생성한 URL을 메모리에 할당했다면 더 이상 사용하지 않을 때 해제 해줘야겠죠?

`$effect` 또한 클린업 함수가 존재하고 언마운트 됐을 시 사용되지 않는 값들을 초기화시킬 수 있습니다.


 

마무리

 

간단 하지만 언제 메모리를 할당하고 해제해야 할지를 판단하는게 중요한 부분입니다.

다음은 간단한 데이터 생성/제거 테스트를 하는 방법에 대한 포스팅입니다.