WeakMap Patterns for Leak-Free Code
Imagine a web app that autosaves user data, caches objects for speed, and attaches metadata to DOM nodes. You need fast lookups without turning your cache into a memory black hole.
Why WeakMap Matters
A regular Map holds strong references to its keys and values. Even if the key object is no
longer used elsewhere, it stays alive inside the map. Over time, these orphaned entries accumulate and leak
memory.
A WeakMap, on the other hand, holds weak references to its keys. If there are no other
references to a key object, the GC can reclaim both the object and its associated entry in the
WeakMap automatically.
Core Characteristics
- Keys must be objects (no primitives).
- Values can be anything.
- Non-enumerable: you can’t loop over entries, preventing accidental retention.
- No
size,keys(), orforEach(). This is by design, so GC can collect safely.
Real-World Use Case: Metadata for DOM Nodes
Suppose you’re building a rich text editor. You need to store extra info for certain nodes, like whether a user has edited a paragraph, but you don’t want to attach properties directly to DOM elements or worry about cleanup when a node is removed.
const nodeMeta = new WeakMap();
function annotate(node, info) {
nodeMeta.set(node, info);
}
function getMeta(node) {
return nodeMeta.get(node);
}
// Usage
const para = document.createElement('p');
annotate(para, { edited: true });
// Later, if `para` is removed and no references remain,
// GC reclaims both the DOM node and its metadata entry.
No manual delete calls. No risk of stale entries.
Pattern: Caching API Responses
You fetch user profiles and cache them to avoid repeat network calls. Using a Map can leak if
you never prune old entries. With WeakMap, you tie cache entries to user objects. Once the user
object falls out of scope, the cache entry goes too.
const profileCache = new WeakMap();
async function getUserProfile(user) {
if (profileCache.has(user)) {
return profileCache.get(user);
}
const profile = await fetch(`/api/users/${user.id}`).then(r => r.json());
profileCache.set(user, profile);
return profile;
}
When user is no longer referenced, its cache entry vanishes.
Common Pitfalls and Tips
- No iteration:
WeakMapdoesn’t expose its entries. Use it when you don’t need to list all keys. - Avoid primitive keys: only objects work.
- Beware of hidden leaks: storing objects in closures or arrays still counts as strong references.
When Not to Use WeakMap
There are cases where WeakMap isn’t the right tool:
- Iteration or inspection needed
If you must list all keys or values, say, to generate a report of cached entries, you need aMapor other structure that exposes its contents.// ❌ WeakMap has no .keys() or .size // ✅ Use Map if you need to log all sessions: const sessionMap = new Map(); // ... console.log(`Active sessions: ${sessionMap.size}`); - Primitive keys required
WeakMap only accepts objects as keys. If your domain uses strings or numbers as identifiers,WeakMapwon’t work.// ❌ Invalid: WeakMap can’t use string keys const m = new WeakMap(); m.set('user123', { name: 'Bob' }); // TypeError - Deterministic cleanup or size tracking
You can’t control exactly when the GC runs or when entries disappear. If you need to know when items are removed or track the number of entries, a standardMapwith manual cleanup is safer.// ❌ WeakMap doesn’t fire events on deletion // ✅ Use Map if you need to trigger actions on removal: const cache = new Map(); // manual delete and callback - Persistent or serializable cache
WeakMap entries vanish without notice and aren’t serializable. For data you must persist or transfer (e.g. saving to IndexedDB), use a plain object, Map, or other storage.
In these scenarios, choose collections that give you full control over their contents and lifecycle.
Conclusion
WeakMap is a powerful tool for managing memory in JavaScript. It lets you associate data with
objects without preventing garbage collection, making it ideal for metadata, caches, and temporary storage.
By understanding its strengths and limitations, you can write cleaner, more efficient code that avoids
memory leaks.
What’s Next
But WeakMap isn’t the only weak structure in town. In the next post, we’ll explore WeakSet, its similarities, its quirks, and the subtle ways it lets you track objects without ever holding them back.