I have a subscription management in my ko model, which saves any subscription by intercepting them and saving reference to them.
I then dispose() them, but I need to understand sometimes if a sub is already disposed. Is the member Gb, a boolean of the subscription object, an active-inactive flag? I see that sometimes when I dispose a subscription its Gb becomes false, sometimes not. Do I have to interpret this as a dispose fail?
And once I dispose a subscription, the subscription object, is ready to be garbage collected?
EDIT: I just need to understand if a subscription is already disposed, as said in the title. I obtain the subscription in the only way I know, saving a reference to it when declared:
var mySub = myObservable.subscribe(function(){/*do something*/});
Some time after I need a way to determine if mySub is already disposed.
function isDisposed(mySubscription) {
// if is disposed return true else return false
}
I need to perform some logic based on this, not only dispose it if it is not disposed already (or I could simply call again the dispose method). Is it possible to determine subsbcription disposal status?
About manual subscriptions
Knockout source is compiled with Google Closure Compiler so only properties and methods explicetly exported in source appear in compiled library code.
With that said a subscription has a "private" property isDisposed
, but it is not exported. Thus the only API exported for subscription is dispose
.
Glimps of source code - ko.subscription (knockout-3.1.0.debug):
ko.subscription = function (target, callback, disposeCallback) {
this.target = target;
this.callback = callback;
this.disposeCallback = disposeCallback;
this.isDisposed = false;
ko.exportProperty(this, 'dispose', this.dispose);
};
ko.subscription.prototype.dispose = function () {
this.isDisposed = true;
this.disposeCallback();
};
About memory leaks and computeds
1) Just an interesting fact about computeds - consider the following computed
var myObservable1 = ko.observable(true);
var myObservable2 = ko.observable('foo');
var myComputed = ko.computed(function () {
if (myObservable1()) {
return myObservable2() + 'bar';
}
});
In this example myComputed
has 2 dependecies. But if we were to assing false
to myObservable1
myComputed
would reevaluate and after reevalution it would only have 1 dependency and subscription to myObservable2
would be disposed.
Why it is disposed:
The explanation lies in how computed is evaluated - it registers dependencies the following way - if any observable is read (meaning code like myObservable1()
) during evaluation - computed recieves a callback with this observable, checks its id and stores it in a new dependency array. Once evaluation is complete - old dependency array is disposed. In our example when myObservable1
is set to false myObservable2
is never read - since we never enter if block. So it is not a new dependecy and old dependency is disposed.
2) Another interesting fact. Consider snippet:
(function () {
var myObservable = ko.observable(0);
var myModel = {
myComputed: ko.computed(function () {
console.log(myObservable());
})
};
myModel = undefined;
myObservable(42); // Outputs 42
})();
The computed is not collected by garbage collector because infact the reference to it exists inside it's dependency.
Glimps of source code - ko.computed (knockout-3.1.0.debug):
function addSubscriptionToDependency(subscribable, id) {
if (!_subscriptionsToDependencies[id]) {
_subscriptionsToDependencies[id] = subscribable.subscribe(evaluatePossiblyAsync);
++_dependenciesCount;
}
}
...
function evaluatePossiblyAsync() {
var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
clearTimeout(evaluationTimeoutInstance);
evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
} else if (dependentObservable._evalRateLimited) {
dependentObservable._evalRateLimited();
} else {
evaluateImmediate();
}
}
Reference to dependentObservable is preserved because reference to evaluatePossiblyAsync is preserved (Closures, JS and all that Jazz).
Whoa, that is all I had to say. Hope some thought come to mind.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With