2015-02-02 13 views
6

Tôi có câu hỏi nhanh về việc thêm/xóa người nghe của đối tượng DOM. Tôi muốn hỏi liệu bộ thu gom rác có thể thu thập bộ nhớ khi xóa các phần tử khỏi trang hay không.thêm/xóa người nghe trên javascript (bộ thu gom rác)

ví dụ: một thẻ <ul> với một danh sách vài trẻ em (<li>)

var ul = document.getElementById('someParent'); 
var children = ul.children; 
var someFunction = function() {}; 

for(var i = 0; i < children.length; i++) { 
    children[i].addEventListener('click', someFunction); 
} 


// This is where I am not sure, would the garbage collector be able to collect 
// the memory allocated on adding listener on children, 
// if I remove the ul tag? 
ul.remove(); 
+0

Vòng lặp của bạn sẽ không hoạt động chính xác. 'children.length' không phải là điều kiện tốt. – Luka

+0

chỉ là lỗi đánh máy, sẽ chỉnh sửa nó nhờ :) – olanchuy

Trả lời

3

Dòng ul.remove(); sẽ loại bỏ ul phần tử và tất cả các con của nó từ DOM. Nhưng bộ nhớ cho người nghe sự kiện sẽ không được phát hành miễn là bạn có tham chiếu đến những người nghe đó, yếu tố li và yếu tố ul. Mà bạn có trong các biến số children, someFunctionul.

Nếu bạn muốn cho các bộ thu rác làm sạch tất cả trong số này, bạn có thể làm ví dụ:

ul.remove(); 
children = null; 
someFunction = null; 
ul = null; 

Bằng cách đó biến children sẽ không giữ tham chiếu đến những yếu tố này, và nếu bạn không có bất kỳ biến nào khác trong mã của bạn giữ tham chiếu cho các phần tử đó, bộ thu gom rác sẽ thu thập chúng. Giữ nguyên cho số someFunction. Lưu ý rằng ul yếu tố giữ tất cả các tham chiếu đến con và người nghe của nó, vì vậy ul cũng phải được làm sạch.

+0

Tôi hiểu, điều đó có ý nghĩa. Nếu đó là một chức năng nặc danh, nó sẽ ổn thôi? – olanchuy

+0

Có, đối với chức năng ẩn danh, nó sẽ ổn thôi. Chỉ cần đảm bảo rằng 'trẻ em 'cũng sạch sẽ. – Luka

+0

Tôi hiểu, tôi bị ngứa ngáy trong tâm trí của mình trước khi điều này xảy ra và nó không biến mất. Cảm ơn đã giúp đỡ. :) – olanchuy

1

Nếu ai đó có thể xác nhận điều này cho tôi, tôi đánh giá cao điều đó.

Từ sự hiểu biết của tôi, nó sẽ được thu gom rác. Theo số MDN Memory Management

Thuật toán thu gom rác thải chủ yếu dựa vào khái niệm tham chiếu. Trong bối cảnh quản lý bộ nhớ, một đối tượng được cho là tham chiếu đến một đối tượng khác nếu đối tượng cũ có quyền truy cập vào đối tượng thứ hai (hoặc ngầm hoặc rõ ràng). Ví dụ, một đối tượng JavaScript có một tham chiếu đến nguyên mẫu của nó (tham chiếu ngầm) và các giá trị thuộc tính của nó (tham chiếu rõ ràng).

Về cơ bản nếu DOM không thể tìm thấy tham chiếu đến phần tử đã nói, nó sẽ thu thập rác trong thời gian tới. Nhìn vào đặc tả chuẩn của DOM về cách hoạt động của .remove(), nó sẽ chạy một loạt các bước sẽ thiết lập các chỉ mục mới của cha mẹ và anh chị em loại bỏ tất cả các tham chiếu đến phần tử.

Vì không có tham chiếu đến phần tử đã nói, nó sẽ được thu gom rác. Trong ví dụ của bạn, bạn đang thêm eventListeners chỉ cho con của phần tử <ul> cụ thể mà bạn đã tạo. Khi bạn loại bỏ một phần tử, bạn cũng loại bỏ tất cả các tham chiếu về con của nó (tôi nghĩ điều này rõ ràng hơn trong các bước trong liên kết ở trên nơi chúng thực sự thiết lập chỉ mục cha trỏ đến chính nó).

EDIT: @contrabit là đúng mặc dù. Tôi không thấy bạn đã lưu trữ children của bạn trong một biến. Miễn là họ là một tham chiếu đến họ, họ sẽ không được thu gom rác thải.

2

Không hề, bạn có thể truy cập vào biến ul ở một nơi khác. Ví dụ dưới đây cho thấy điều đó.

var ul = document.getElementById('someParent'); 
ul.remove(); 
console.log(ul); // ul and all li tags 
document.body.appendChild(ul); // ul appears again 

Ví dụ này không phải là trường hợp bình thường.Trường hợp thông thường là bạn muốn truy cập một tham chiếu DOM trong một sự kiện nói "click button". Tham chiếu đó sẽ luôn có sẵn miễn là sự kiện không phải là không liên kết. Ví dụ:

var ul = document.getElementById('someParent'); 
var myButton = document.getElementById('myButton'); 
myButton.addEventListener('click', function() { 
    ul.innerHTML += '<li>Some text</li>' 
}); 
ul.remove(); 
myButton.click(); // no exception when execting button click event 

Để tránh rò rỉ bộ nhớ trong JS:

  1. đảm bảo rằng không có tài liệu tham khảo DOM bằng cách sử dụng jQuery cho ví dụ.
  2. nếu bạn sử dụng các tham chiếu DOM trong ứng dụng của bạn, đặt chúng thành null hoặc không xác định khi chúng không được sử dụng.

Vì vậy, bạn có thể sửa đổi sự kiện của mình một chút như bên dưới.

myButton.addEventListener('click', function() { 
    // check ul belongs to visible DOM 
    if (!document.body.contains(ul)) { 
     ul = null; 
     return; 
    } 
    ul.innerHTML += '<li>Some text</li>' 
});