diff --git a/packages/@lwc/engine-core/src/framework/weak-multimap.ts b/packages/@lwc/engine-core/src/framework/weak-multimap.ts index 0044be5921..947565dfda 100644 --- a/packages/@lwc/engine-core/src/framework/weak-multimap.ts +++ b/packages/@lwc/engine-core/src/framework/weak-multimap.ts @@ -7,50 +7,16 @@ import { ArrayPush, ArraySplice, isUndefined } from '@lwc/shared'; -const supportsWeakRefs = - typeof WeakRef === 'function' && typeof FinalizationRegistry === 'function'; - /** * A map where the keys are weakly held and the values are a Set that are also each weakly held. * The goal is to avoid leaking the values, which is what would happen with a WeakMap>. * * Note that this is currently only intended to be used in dev/PRODDEBUG environments. - * It leaks in legacy browsers, which may be undesired. + * + * This implementation relies on WeakRefs and FinalizationRegistry. + * For some background, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef */ -export interface WeakMultiMap { - get(key: T): ReadonlySet; - add(key: T, vm: V): void; - delete(key: T): void; -} - -// In browsers that doesn't support WeakRefs, the values will still leak, but at least the keys won't -class LegacyWeakMultiMap implements WeakMultiMap { - private _map: WeakMap> = new WeakMap(); - - private _getValues(key: K): Set { - let values = this._map.get(key); - if (isUndefined(values)) { - values = new Set(); - this._map.set(key, values); - } - return values; - } - - get(key: K): ReadonlySet { - return this._getValues(key); - } - add(key: K, vm: V) { - const set = this._getValues(key); - set.add(vm); - } - delete(key: K) { - this._map.delete(key); - } -} - -// This implementation relies on the WeakRef/FinalizationRegistry proposal. -// For some background, see: https://github.com/tc39/proposal-weakrefs -class ModernWeakMultiMap implements WeakMultiMap { +export class WeakMultiMap { private _map = new WeakMap[]>(); private _registry = new FinalizationRegistry((weakRefs: WeakRef[]) => { @@ -88,8 +54,12 @@ class ModernWeakMultiMap implements WeakMult } add(key: K, value: V) { const weakRefs = this._getWeakRefs(key); - // We could check for duplicate values here, but it doesn't seem worth it. - // We transform the output into a Set anyway + // Skip adding if already present + for (const weakRef of weakRefs) { + if (weakRef.deref() === value) { + return; + } + } ArrayPush.call(weakRefs, new WeakRef(value)); // It's important here not to leak the second argument, which is the "held value." The FinalizationRegistry @@ -105,5 +75,3 @@ class ModernWeakMultiMap implements WeakMult this._map.delete(key); } } - -export const WeakMultiMap = supportsWeakRefs ? ModernWeakMultiMap : LegacyWeakMultiMap;