我最近在Angular的指令中遇到了一些问题,没有正确清理,因此造成内存泄漏。
所以,今天,当我正在进行测试以确保不会发生时,我意识到没有办法停止观察。
var stopObserving = attrs.$observe('myProperty', function(newValue) {
updateElement(newValue);
});
因为我认为它在$watch
上的工作方式与它相同,但很明显它没有。根据文档,$observe
将返回回调函数,就是它,第二个参数。
我有这个测试:
describe('destroy',function(){
beforeEach(function(){
$scope.$destroy();
});
it('should have emptied the DOM node', function(){
expect(element.text()).toBe('');
});
it('shouldn\'t have any more watchers', function(){
dump(element.data().$scope.$$watchers);
expect(element.data().$scope.$$watchers.length).toBe(0);
});
});
它失败了,因为有一个观察者。我检查了$destroy
被调用,因此,清理完成了。但是,我怎样才能摆脱那个观察者?
代码,如果你好奇的话就在这里:
答案 0 :(得分:18)
在Angular 1.3及以上版本中,$observe returns the deregister function,因此取消注册$ observe与$ watch完全相同:
var stopObserving = attrs.$observe(...);
stopObserving();
在AngularJs 1.2中,没有办法取消注册观察者,正如你正确指出的那样,$ observe返回回调函数。
然而,目前有一个PR可以更改$ observe以返回类似于$ watch和$ on的注销功能,不幸的是,由于突破性的变化,这只是针对1.3版本进行了分类。 PR超过here:https://github.com/angular/angular.js/pull/5609
好消息是,根据PR,需要完整的3行代码来实现更改,所以如果您不能等到1.3版本,您可以自己轻松实现。
答案 1 :(得分:2)
当您调用$ watch()方法时,要创建绑定,AngularJS将返回“注销”功能。然后可以使用此函数解除绑定$ watch()侦听器 - 您只需调用此返回的函数,并删除$ watch()侦听器。 要查看此操作,请查看以下代码。在此演示中,我们正在观察链接所获得的点击次数。并且,如果该数字超过5,我们将显示一条消息;但是,一旦显示消息,我们就会删除监听器,因为它将不再具有任何值。
访问:http://plnkr.co/edit/nciFRm9HTL3i8xYSUQJa?p=preview
如您所见,我们存储了$ watch()语句返回的函数引用;然后,一旦$ watch()触发几次,我们调用该存储的方法,取消绑定$ watch()监听器。如果您观察控制台日志,则可以看到一旦调用“注销”功能,console.log()语句就会停止。
答案 2 :(得分:2)
作为临时解决方案,您可以这样做:
var key = 'myAttr';
attrs.$observe(key, function(newValue) {
updateElement(newValue);
delete attrs.$$observers[key];
});
或者如果你想要真的很漂亮:
attrs.$observe = function(key, fn) {
attrs.$observe(key, fn);
return function() {
delete attrs.$$observers[key];
};
}
var unobserve = attrs.$observe('myAttr', function(newValue){
updateElement(newValue);
unobserve();
});