WeakMap의 사용처

자바스크립트 세부사항 스터디

Posted by jopemachine on November 24, 2021 Updated on September 27, 2022

WeakMap의 사용처

  • WeakMap이란 키가 약하게 참조되는 키/쌍의 컬렉션이다.

  • 이걸 어디에 쓰냐? 키가 가비지 컬렉션 되지 않았을 때만 의미 있는 정보를 저장할 때 (키가 가비지 컬렉팅 되면 자동으로 맵에서 제거) 쓴다.

  • 그런 상황이 어디인가? => 예를 들어 이런 캐싱 라이브러리 (mem) 구현에 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...

const cacheStore = new WeakMap<AnyFunction, CacheStorage<any, any>>();

export default function mem<
	FunctionToMemoize extends AnyFunction,
	CacheKeyType,
>(
	fn: FunctionToMemoize,
	{
		cacheKey,
		cache = new Map(),
		maxAge,
	}: Options<FunctionToMemoize, CacheKeyType> = {},
): FunctionToMemoize {
	if (typeof maxAge === 'number') {
		mapAgeCleaner(cache as unknown as Map<CacheKeyType, ReturnType<FunctionToMemoize>>);
	}

	const memoized = function (this: any, ...arguments_: Parameters<FunctionToMemoize>): ReturnType<FunctionToMemoize> {
		const key = cacheKey ? cacheKey(arguments_) : arguments_[0] as CacheKeyType;

		const cacheItem = cache.get(key);
		if (cacheItem) {
			return cacheItem.data; // eslint-disable-line @typescript-eslint/no-unsafe-return
		}

		const result = fn.apply(this, arguments_) as ReturnType<FunctionToMemoize>;

		cache.set(key, {
			data: result,
			maxAge: maxAge ? Date.now() + maxAge : Number.POSITIVE_INFINITY,
		});

		return result; // eslint-disable-line @typescript-eslint/no-unsafe-return
	} as FunctionToMemoize;

	mimicFn(memoized, fn, {
		ignoreNonConfigurable: true,
	});

	cacheStore.set(memoized, cache);

	return memoized;
}
  • Map -> 값은 키를 강하게 참조 (키는 가비지 컬렉션의 대상이 절대 될 수 없음), WeakMap -> 값은 키를 약하게 참조 (값 이외에 참조가 없다면 가비지 컬렉션 된다.)

  • 따라서, cacheStoreWeakMap 대신 Map을 쓰면, 맵 객체는 실행이 끝나 가비지 컬렉션 된 함수들이 계속 키로 저장되면서 메모리 누수가 발생한다.

  • 약한 참조를 사용하는 WeakMap을 사용하면 실행이 끝난 함수들이 알아서 맵에서 제거됨.

  • WeakMap 객체는 약한 참조를 사용하기 때문에 Object.keys, Object.values 같은 메서드로 키, 값 목록을 가져올 수 없음. (그냥 빈 배열을 리턴하는 듯?)