Knockout.js 淘汰订阅洞察:检测是否已释放
我的ko模型中有一个订阅管理,它通过截取订阅并保存对它们的引用来保存任何订阅 然后我处理()它们,但有时我需要了解是否已经处理了sub。成员Gb(订阅对象的布尔值)是否为活动-非活动标志?我看到,有时当我处理订阅时,它的Gb变为false,有时则不是。我是否必须将其解释为处置失败 一旦我处理了订阅,订阅对象就可以被垃圾收集了吗 编辑:我只需要了解订阅是否已被处置,如标题中所述。我以我知道的唯一方式获取订阅,并在声明时保存对它的引用:Knockout.js 淘汰订阅洞察:检测是否已释放,knockout.js,subscriptions,singlepage,Knockout.js,Subscriptions,Singlepage,我的ko模型中有一个订阅管理,它通过截取订阅并保存对它们的引用来保存任何订阅 然后我处理()它们,但有时我需要了解是否已经处理了sub。成员Gb(订阅对象的布尔值)是否为活动-非活动标志?我看到,有时当我处理订阅时,它的Gb变为false,有时则不是。我是否必须将其解释为处置失败 一旦我处理了订阅,订阅对象就可以被垃圾收集了吗 编辑:我只需要了解订阅是否已被处置,如标题中所述。我以我知道的唯一方式获取订阅,并在声明时保存对它的引用: var mySub = myObservable.subscr
var mySub = myObservable.subscribe(function(){/*do something*/});
一段时间后,我需要一种方法来确定mySub是否已被处置
function isDisposed(mySubscription) {
// if is disposed return true else return false
}
我需要在此基础上执行一些逻辑,而不仅仅是在它还没有被处理的情况下处理它(或者我可以简单地再次调用dispose方法)。是否可以确定子订阅处理状态?关于手动订阅 敲除源代码是用Google闭包编译器编译的,所以只有在源代码中明确导出的属性和方法才会出现在编译后的库代码中 因此,订阅具有“私有”属性
isDisposed
,但不会导出。因此,为订阅导出的唯一API是dispose
源代码的一瞥-ko.subscription(knockout-3.1.0.debug):
关于内存泄漏和计算的信息
1)关于计算机的一个有趣的事实——考虑下面计算的
var myObservable1 = ko.observable(true);
var myObservable2 = ko.observable('foo');
var myComputed = ko.computed(function () {
if (myObservable1()) {
return myObservable2() + 'bar';
}
});
在本例中,mycomputerd
有两个依赖项。但是,如果我们将false
分配给myObservable1
mycomputer
将重新评估,重新评估后,它将只有1个依赖项,而myObservable2
的订阅将被处置
处置原因:
解释在于如何计算computed-它以以下方式注册依赖关系-如果在计算过程中读取了任何observable(意思是类似于myObservable1()
)的代码-computed接收带有此observable的回调,检查其id并将其存储在新的依赖关系数组中。一旦计算完成,旧的依赖项数组就会被释放。在我们的示例中,当myObservable1
设置为false时,从不读取myObservable2
,因为我们从不输入if块。所以它不是一个新的依赖项,旧的依赖项被处理掉了
2) 另一个有趣的事实。考虑片段:
(function () {
var myObservable = ko.observable(0);
var myModel = {
myComputed: ko.computed(function () {
console.log(myObservable());
})
};
myModel = undefined;
myObservable(42); // Outputs 42
})();
垃圾收集器不会收集计算的,因为实际上对它的引用存在于它的依赖项中
源代码的一瞥-ko.computed(knockout-3.1.0.debug):
对DependentToServable的引用被保留,因为对evaluatePossiblyAsync的引用被保留(闭包、JS和所有这些)
哇,这就是我要说的。希望我能想到一些想法。确定一个活动的
计算的是否已被处理的一个确定的方法是查看一个可观察对象有多少订阅
在这里,看一看:
>>> y = ko.observable()
>>> y.getSubscriptionsCount()
0
>>> x = ko.computed(function () { y() })
>>> y.getSubscriptionsCount()
1
>>> x.dispose()
>>> y.getSubscriptionsCount()
0
请注意,对于pure
computes,当pure compute处于休眠状态(即没有订阅)时,getsubscriptionscont
将为0
。i、 e
>>> x = ko.pureComputed(function () { y() })
>>> y.getSubscriptionsCount()
0
>>> z = x.subscribe(console.log.bind(console))
>>> y.getSubscriptionsCount()
1
换言之,纯计算机可能在他们仅仅睡觉的时候被处理掉
你可以通过订阅一个纯计算机来唤醒它;如果依赖项的订阅计数仍然为零,则必须将其释放。您的问题不清楚。您能否提供用于拦截订阅的代码?你为什么这么做?knockout中的订阅只是订阅对象订阅数组中的一项。所以,当subscribable存在时,garbadge collector不会收集订阅者。无论如何,请澄清事实是,我将每个订阅存储在一个数组中,在我的模型中。当我删除带有cleanNode的模型时,IE6中会出现内存泄漏,因此我尝试使用dispose()销毁订阅数组中每个项目上的所有订阅,然后执行cleanNode。我只希望在dispose阶段能够区分已处理的订阅和未处理的订阅,因为某些模型可能希望自己处理订阅,因为他们不知道我正在对dropModel自定义函数()中存储的所有订阅执行此操作订阅有一个属性isDisposed
,但它未在ko的生产版本中导出(该版本不可使用)。但从源代码来看,多次调用dispose并没有什么错。调用订阅的dispose会导致订阅(目标)从数组中删除订阅:`var subscription=new ko.subscription(self,boundCallback,function(){ko.utils.arrayremovietem(self._subscriptions[event],subscription);})`这有用吗,请告诉我。关于内存泄漏——如果您使用的是Computed,那么如果它们的依赖关系没有被处理,则必须手动处理它们。因为计算存储引用了它们的依赖项,而依赖项存储了对计算对象的引用。是的,这很有帮助。我负责处理每一个手动订阅和computed/pureComputed with dispose(),但我担心手动订阅的某些内容仍然存在。在subscription对象中,我可以在da()对象中找到,这是可观察的subscription对象。即使在处理订阅时也可能泄漏内存?如果我不能使用isDisposed,我就不能得到我需要的东西,特别是现在我们了解到,一次订阅处理两次是不合适的?解释得很好。但是,有两件事:使用ko.pureComputed
订阅会自动处理(或者说,我想是文档中说的,ko 3.2+),第二件事:您能解释一下为什么在案例2中会处理对myObservable2
的订阅吗??当你说“w”
>>> y = ko.observable()
>>> y.getSubscriptionsCount()
0
>>> x = ko.computed(function () { y() })
>>> y.getSubscriptionsCount()
1
>>> x.dispose()
>>> y.getSubscriptionsCount()
0
>>> x = ko.pureComputed(function () { y() })
>>> y.getSubscriptionsCount()
0
>>> z = x.subscribe(console.log.bind(console))
>>> y.getSubscriptionsCount()
1