gotchajavascriptModeratepending
Gotcha: JavaScript WeakRef and FinalizationRegistry caveats
Viewed 0 times
WeakRefFinalizationRegistrygarbage-collectionderefnon-deterministic
Error Messages
Problem
WeakRef and FinalizationRegistry have unpredictable timing and behavior because garbage collection is non-deterministic.
Solution
Understand the limitations of weak references:
// WeakRef - holds a reference that doesn't prevent GC:
let obj = { data: 'important' };
const weakRef = new WeakRef(obj);
obj = null; // Eligible for GC
// Later (GC may or may not have run):
const derefed = weakRef.deref();
if (derefed) {
console.log(derefed.data); // May or may not work!
}
// Gotchas:
// 1. deref() may return undefined at ANY time after obj is unreachable
// 2. GC timing is NOT predictable - don't rely on it
// 3. Never use WeakRef for important data flow
// 4. deref() in the same turn is guaranteed to return the object
// FinalizationRegistry - cleanup callback when object is GC'd:
const registry = new FinalizationRegistry((heldValue) => {
console.log(
// Clean up external resources
});
registry.register(obj, 'my-key');
// Gotchas:
// 1. Callback may never run (browser tab closed first)
// 2. Callback timing is unpredictable
// 3. Don't use for critical cleanup - use try/finally instead
// 4. Callback runs in a microtask, not immediately
// Valid use case: Cache that doesn't prevent GC
// Invalid use case: Anything that MUST happen (use explicit cleanup)
// WeakRef - holds a reference that doesn't prevent GC:
let obj = { data: 'important' };
const weakRef = new WeakRef(obj);
obj = null; // Eligible for GC
// Later (GC may or may not have run):
const derefed = weakRef.deref();
if (derefed) {
console.log(derefed.data); // May or may not work!
}
// Gotchas:
// 1. deref() may return undefined at ANY time after obj is unreachable
// 2. GC timing is NOT predictable - don't rely on it
// 3. Never use WeakRef for important data flow
// 4. deref() in the same turn is guaranteed to return the object
// FinalizationRegistry - cleanup callback when object is GC'd:
const registry = new FinalizationRegistry((heldValue) => {
console.log(
Object with key ${heldValue} was GC'd);// Clean up external resources
});
registry.register(obj, 'my-key');
// Gotchas:
// 1. Callback may never run (browser tab closed first)
// 2. Callback timing is unpredictable
// 3. Don't use for critical cleanup - use try/finally instead
// 4. Callback runs in a microtask, not immediately
// Valid use case: Cache that doesn't prevent GC
// Invalid use case: Anything that MUST happen (use explicit cleanup)
Why
WeakRef and FinalizationRegistry are for optimization hints only. They must never be the only mechanism for important cleanup.
Revisions (0)
No revisions yet.