Skip to content

Commit db87c3e

Browse files
committed
Avoid cascading unsubscribes
Fixes #274
1 parent 458f816 commit db87c3e

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

packages/core/src/index.ts

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -219,18 +219,21 @@ Signal.prototype._subscribe = function (node) {
219219
};
220220

221221
Signal.prototype._unsubscribe = function (node) {
222-
const prev = node._prevTarget;
223-
const next = node._nextTarget;
224-
if (prev !== undefined) {
225-
prev._nextTarget = next;
226-
node._prevTarget = undefined;
227-
}
228-
if (next !== undefined) {
229-
next._prevTarget = prev;
230-
node._nextTarget = undefined;
231-
}
232-
if (node === this._targets) {
233-
this._targets = next;
222+
// Only run the unsubscribe step if the signal has any subscribers to begin with.
223+
if (this._targets !== undefined) {
224+
const prev = node._prevTarget;
225+
const next = node._nextTarget;
226+
if (prev !== undefined) {
227+
prev._nextTarget = next;
228+
node._prevTarget = undefined;
229+
}
230+
if (next !== undefined) {
231+
next._prevTarget = prev;
232+
node._nextTarget = undefined;
233+
}
234+
if (node === this._targets) {
235+
this._targets = next;
236+
}
234237
}
235238
};
236239

@@ -464,18 +467,22 @@ Computed.prototype._subscribe = function (node) {
464467
};
465468

466469
Computed.prototype._unsubscribe = function (node) {
467-
Signal.prototype._unsubscribe.call(this, node);
468-
469-
// Computed signal unsubscribes from its dependencies from it loses its last subscriber.
470-
if (this._targets === undefined) {
471-
this._flags &= ~TRACKING;
472-
473-
for (
474-
let node = this._sources;
475-
node !== undefined;
476-
node = node._nextSource
477-
) {
478-
node._source._unsubscribe(node);
470+
// Only run the unsubscribe step if the computed signal has any subscribers.
471+
if (this._targets !== undefined) {
472+
Signal.prototype._unsubscribe.call(this, node);
473+
474+
// Computed signal unsubscribes from its dependencies when it loses its last subscriber.
475+
// This makes it possible for unreferences subgraphs of computed signals to get garbage collected.
476+
if (this._targets === undefined) {
477+
this._flags &= ~TRACKING;
478+
479+
for (
480+
let node = this._sources;
481+
node !== undefined;
482+
node = node._nextSource
483+
) {
484+
node._source._unsubscribe(node);
485+
}
479486
}
480487
}
481488
};

0 commit comments

Comments
 (0)