knockout/knockout — pull request #1359 by mbest (2014-04-18 20:56:20+00:00)
Title: Proposal: new computed variant that's "active" only when observed

Currently, a computed observable, once activated, remains active until one of the following happen:

1. It is manually disposed by calling its `dispose` method.
2. The DOM node specified using `disposeWhenNodeIsRemoved` is removed or cleaned.
3. When a dependency changes, the `disposeWhen` function returns `true`.
4. When a dependency changes, the `read` function returns without accessing any observables.

To clarify, *active* means that the computed observable is subscribed to one or more other observables and is updated when any of those are changed. This is important to understand because it means that an active computed observable cannot be garbage collected until all references to both it and all of its dependencies are dropped in an application. **This could result in a memory leak if, for example, a computed observable references observables outside its own view model.**

I'm proposing a new computed observable mode in which it only maintains subscriptions to its dependencies when it also has subscribers. When it has subscribers, it will act just like a "normal," active computed observable, **But as soon as it has no subscribers, it will "dispose" its subscriptions and enter an inactive, "sleeping" state.**

These are the states that a computed observable can currently be in (not counting intermediate states while it is updating):

1. Created, but waiting to fully initialize (only when using the `deferEvaluation` option).
2. Initialized and waiting for changes to its dependencies (normal, active state).
3. Scheduled to update after dependencies have changed (when using `throttle` or `rateLimit` extenders).
4. Disposed, with no dependencies and no chance for future updates (also called "inactive").

This feature will add a new computed observable state:

* "Sleeping", waiting for subscriptions, during which the computed observable will be re-calculated when it is accessed and will not subscribe to any observables. This will also always be the initial state of the computed observable.