Как остановить $наблюдать в AngularJS
Недавно у меня возникли некоторые проблемы с плагинами jQuery в директивах в 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
Ответы
Ответ 1
AngularJS 1.3 и выше
В Angular 1,3 и выше $observ возвращает функцию deregister, поэтому отмена регистрации $наблюдается так же, как и для $watch:
var stopObserving = attrs.$observe(...);
stopObserving();
AngularJS 1.2 и ниже
В AngularJs 1.2 нет возможности отменить регистрацию наблюдателя, и, как вы правильно заметили, функция $observ возвращает функцию обратного вызова.
Однако в настоящее время PR открыт для изменения $watch, чтобы также вернуть функцию дерегистрации, аналогичную $watch и $on, к сожалению, это только триггером для версии 1.3 из-за изменения разрыва. PR превышает здесь: https://github.com/angular/angular.js/pull/5609
Хорошая новость: для реализации изменения требуется всего 3 новых строки кода, согласно
Ответ 2
Когда вы вызываете метод $watch(), чтобы создать привязку, функция AngularJS возвращает функцию "дерегинга". Затем эту функцию можно использовать для развязки вашего слушателя $watch() - все, что вам нужно сделать, это вызвать эту возвращенную функцию, и ваш слушатель $watch() будет удален.
Чтобы увидеть это в действии, взгляните на следующий код. В этой демонстрации мы наблюдаем количество кликов, которые получает ссылка. И, если это число будет выше 5, мы собираемся показать сообщение; однако, как только сообщение будет показано, мы удалим слушателя, поскольку он больше не будет иметь никакого значения.
посетите: http://plnkr.co/edit/nciFRm9HTL3i8xYSUQJa?p=preview
Как вы можете видеть, мы сохраняем ссылку на функцию, возвращаемую оператором $watch(); то, как только $watch() срабатывает несколько раз, мы вызываем этот хранимый метод, отвязывая прослушиватель $watch(). Если вы смотрите журнал консоли, вы можете видеть, что инструкции console.log() останавливаются, как только вызывается функция "дерегинга".
Ответ 3
как временное решение, которое вы можете сделать:
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();
});