A
WeakRef
object lets you hold a weak reference to another object, without preventing that object from getting garbage-collected.
A
WeakRef
object contains a weak reference to an object, which is called its
target
or
referent
. A
weak reference
to an object is a reference that does not prevent the object from being reclaimed by the garbage collector. In contrast, a normal (or
strong
) reference keeps an object in memory. When an object no longer has any strong references to it, the JavaScript engine's garbage collector may destroy the object and reclaim its memory. If that happens, you can't get the object from a weak reference anymore.
注意:
Please see the
Avoid where possible
section below. Correct use of
WeakRef
takes careful thought, and it's best avoided if possible.
WeakRef()
WeakRef
对象。
WeakRef.prototype.deref()
WeakRef
object's target object, or
undefined
if the target object has been reclaimed.
Correct use of
WeakRef
takes careful thought, and it's best avoided if possible. It's also important to avoid relying on any specific behaviors not guaranteed by the specification. When, how, and whether garbage collection occurs is down to the implementation of any given JavaScript engine. Any behavior you observe in one engine may be different in another engine, in another version of the same engine, or even in a slightly different situation with the same version of the same engine. Garbage collection is a hard problem that JavaScript engine implementers are constantly refining and improving their solutions to.
Here are some specific points that the authors of the WeakRef proposal included in its explainer document :
Garbage collectors are complicated. If an application or library depends on GC cleaning up a WeakRef or calling a finalizer [cleanup callback] in a timely, predictable manner, it's likely to be disappointed: the cleanup may happen much later than expected, or not at all. Sources of variability include:
Some notes on
WeakRef
s:
WeakRef
for a target object, or has gotten a target object from a
WeakRef
's
deref
method, that target object will not be reclaimed until the end of the current JavaScript
job
(including any promise reaction jobs that run at the end of a script job). That is, you can only "see" an object get reclaimed between turns of the event loop. This is primarily to avoid making the behavior of any given JavaScript engine's garbage collector apparent in code — because if it were, people would write code relying on that behavior, which would break when the garbage collector's behavior changed. (Garbage collection is a hard problem; JavaScript engine implementers are constantly refining and improving how it works.)
WeakRef
s have the same target, they're consistent with one another. The result of calling
deref
on one of them will match the result of calling
deref
on another of them (in the same job), you won't get the target object from one of them but
undefined
from another.
WeakRef
is also in a
FinalizationRegistry
,
WeakRef
's target is cleared at the same time or before any cleanup callback associated with the registry is called; if your cleanup callback calls
deref
on a
WeakRef
for the object, it will receive
undefined
.
WeakRef
, it will always only ever be the original target object or
undefined
when that target has been reclaimed.
WeakRef
might never return
undefined
from
deref
, even if nothing strongly holds the target, because the garbage collector may never decide to reclaim the object.
This example starts a counter shown in a DOM element, stopping when the element doesn't exist anymore:
class Counter {
constructor(element) {
// Remember a weak reference to the DOM element
this.ref = new WeakRef(element);
this.start();
}
start() {
if (this.timer) {
return;
}
this.count = 0;
const tick = () => {
// Get the element from the weak reference, if it still exists
const element = this.ref.deref();
if (element) {
element.textContent = ++this.count;
} else {
// The element doesn't exist anymore
console.log("The element is gone.");
this.stop();
this.ref = null;
}
};
tick();
this.timer = setInterval(tick, 1000);
}
stop() {
if (this.timer) {
clearInterval(this.timer);
this.timer = 0;
}
}
}
const counter = new Counter(document.getElementById("counter"));
counter.start();
setTimeout(() => {
document.getElementById("counter").remove();
}, 5000);
| 规范 |
|---|
|
WeakRefs
The definition of 'WeakRef' in that specification. |
| Desktop | Mobile | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
WeakRef
|
Chrome 84 | Edge 84 | Firefox 79 | IE No | Opera No | Safari No | WebView Android 84 | Chrome Android 84 | Firefox Android No | Opera Android No | Safari iOS No | Samsung Internet Android No |
nodejs
13.0.0
Disabled
|
WeakRef()
构造函数
|
Chrome 84 | Edge 84 | Firefox 79 | IE No | Opera No | Safari No | WebView Android 84 | Chrome Android 84 | Firefox Android No | Opera Android No | Safari iOS No | Samsung Internet Android No |
nodejs
13.0.0
Disabled
|
deref
|
Chrome 84 | Edge 84 | Firefox 79 | IE No | Opera No | Safari No | WebView Android 84 | Chrome Android 84 | Firefox Android No | Opera Android No | Safari iOS No | Samsung Internet Android No |
nodejs
13.0.0
Disabled
|
完整支持
不支持
用户必须明确启用此特征。
WeakRef
Function
Object
Object.prototype.__defineGetter__()
Object.prototype.__defineSetter__()
Object.prototype.__lookupGetter__()
Object.prototype.__lookupSetter__()
Object.prototype.hasOwnProperty()
Object.prototype.isPrototypeOf()
Object.prototype.propertyIsEnumerable()
Object.prototype.toLocaleString()
Object.prototype.toSource()
Object.prototype.toString()
Object.prototype.valueOf()
Object.setPrototypeOf()