如何在AngularJS中停止$ observe

时间:2014-01-04 20:41:56

标签: javascript angularjs angularjs-directive

我最近在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被调用,因此,清理完成了。但是,我怎样才能摆脱那个观察者?

代码,如果你好奇的话就在这里:

https://github.com/firstandthird/angular-popbox

3 个答案:

答案 0 :(得分:18)

AngularJS 1.3及以上

在Angular 1.3及以上版本中,$observe returns the deregister function,因此取消注册$ observe与$ watch完全相同:

var stopObserving = attrs.$observe(...);
stopObserving();

AngularJS 1.2及以下

在AngularJs 1.2中,没有办法取消注册观察者,正如你正确指出的那样,$ observe返回回调函数。

然而,目前有一个PR可以更改$ observe以返回类似于$ watch和$ on的注销功能,不幸的是,由于突破性的变化,这只是针对1.3版本进行了分类。 PR超过herehttps://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();
});