Người nghe sự kiện
Trước hết, điều quan trọng là phải hiểu rằng có hai loại "người nghe sự kiện":
Phạm vi người nghe sự kiện đã đăng ký thông qua $on
:
$scope.$on('anEvent', function (event, data) {
...
});
Trình xử lý sự kiện được đính kèm với các phần tử thông qua ví dụ on
hoặc bind
:
element.on('click', function (event) {
...
});
$ phạm vi. $ phá hủy ()
Khi $scope.$destroy()
được thực thi, nó sẽ xóa tất cả các trình nghe được đăng ký qua $on
trên phạm vi $ đó.
Nó sẽ không loại bỏ các thành phần DOM hoặc bất kỳ trình xử lý sự kiện đính kèm nào thuộc loại thứ hai.
Điều này có nghĩa là việc gọi $scope.$destroy()
thủ công từ ví dụ trong hàm liên kết của lệnh sẽ không xóa trình xử lý được đính kèm qua element.on
, cũng như chính phần tử DOM.
phần tử.remove ()
Lưu ý rằng đó remove
là phương thức jqLite (hoặc phương thức jQuery nếu jQuery được tải trước AngularjS) và không khả dụng trên Đối tượng phần tử DOM tiêu chuẩn.
Khi element.remove()
được thực thi phần tử đó và tất cả các phần tử con của nó sẽ bị xóa khỏi DOM cùng với tất cả các trình xử lý sự kiện được đính kèm qua chẳng hạn element.on
.
Nó sẽ không phá hủy phạm vi $ liên quan đến phần tử.
Để làm cho nó khó hiểu hơn, cũng có một sự kiện jQuery được gọi là $destroy
. Đôi khi, khi làm việc với các thư viện jQuery của bên thứ ba loại bỏ các phần tử hoặc nếu bạn xóa chúng theo cách thủ công, bạn có thể cần phải thực hiện dọn dẹp khi điều đó xảy ra:
element.on('$destroy', function () {
scope.$destroy();
});
Phải làm gì khi chỉ thị bị "phá hủy"
Điều này phụ thuộc vào cách chỉ thị bị "phá hủy".
Một trường hợp bình thường là một lệnh bị hủy vì ng-view
thay đổi chế độ xem hiện tại. Khi điều này xảy ra, lệnh ng-view
sẽ hủy phạm vi $ được liên kết, cắt tất cả các tham chiếu đến phạm vi chính của nó và gọi remove()
phần tử.
Điều này có nghĩa là nếu chế độ xem đó chứa một lệnh với chức năng này trong chức năng liên kết của nó khi nó bị phá hủy bởi ng-view
:
scope.$on('anEvent', function () {
...
});
element.on('click', function () {
...
});
Cả hai người nghe sự kiện sẽ được gỡ bỏ tự động.
Tuy nhiên, điều quan trọng cần lưu ý là mã bên trong các trình nghe này vẫn có thể gây rò rỉ bộ nhớ, ví dụ nếu bạn đã đạt được mẫu rò rỉ bộ nhớ JS phổ biến circular references
.
Ngay cả trong trường hợp bình thường này của một lệnh bị phá hủy do thay đổi chế độ xem, có những thứ bạn có thể cần phải làm sạch bằng tay.
Ví dụ: nếu bạn đã đăng ký một người nghe trên $rootScope
:
var unregisterFn = $rootScope.$on('anEvent', function () {});
scope.$on('$destroy', unregisterFn);
Điều này là cần thiết vì $rootScope
không bao giờ bị phá hủy trong suốt vòng đời của ứng dụng.
Điều tương tự cũng xảy ra nếu bạn đang sử dụng một triển khai pub / sub khác không tự động thực hiện việc dọn dẹp cần thiết khi phạm vi $ bị hủy hoặc nếu lệnh của bạn chuyển các cuộc gọi lại đến các dịch vụ.
Một tình huống khác sẽ là hủy bỏ $interval
/ $timeout
:
var promise = $interval(function () {}, 1000);
scope.$on('$destroy', function () {
$interval.cancel(promise);
});
Nếu chỉ thị của bạn đính kèm các trình xử lý sự kiện vào các thành phần, ví dụ bên ngoài chế độ xem hiện tại, bạn cũng cần phải xóa sạch chúng theo cách thủ công:
var windowClick = function () {
...
};
angular.element(window).on('click', windowClick);
scope.$on('$destroy', function () {
angular.element(window).off('click', windowClick);
});
Đây là một số ví dụ về những việc cần làm khi các chỉ thị bị "phá hủy" bởi Angular, ví dụ bởi ng-view
hoặc ng-if
.
Nếu bạn có các chỉ thị tùy chỉnh quản lý vòng đời của các phần tử DOM, v.v ... tất nhiên nó sẽ phức tạp hơn.