2016-10-04 15 views
8

Tôi muốn tạo động các thành phần góc sử dụng javascript và sau đó biên dịch góc bằng cách sử dụng $compile với phạm vi mới được tạo. Sau đó, khi tôi không còn sử dụng cho thành phần đó, tôi muốn phá hủy thành phần và phạm vi mới.

Mọi thứ hoạt động như mong đợi, ngoại trừ thực tế là mặc dù tôi đang phá hủy phạm vi mới, tất cả bộ nhớ mà nó sử dụng sẽ không bao giờ được phát hành.

Dưới đây là một phần của một phiên bản đơn giản hóa của mã mà:

app.controller("mainCtrl", ["$scope", "$compile", function($scope, $compile) { 
    var childScope; 

    //call this every time the button is clicked 
    this.createDirective = function() { 
     //dynamically create a new instance of the custom directive 
     var customDirective = document.createElement("custom-directive"); 

     //if another child scope exists, destroy it 
     if (childScope) { 
      childScope.$destroy(); 
      childScope = undefined; 
     } 

     //create a new child scope 
     childScope = $scope.$new(); 

     //compile the custom directive 
     $compile(customDirective)(childScope); 
    }; 

}]); 

Full dụ làm việc của mã này là here

Tất cả các mã này không, là tạo ra một thành phần mới mỗi khi nút được click , nhưng trước tiên hãy hủy mọi thành phần đã tồn tại. Lưu ý rằng tôi không thực sự thêm thành phần được biên dịch vào trang, vì tôi nhận thấy rằng sự rò rỉ vẫn ở đó bất kể tôi có sử dụng nó hay không.

Sử dụng công cụ phát triển của Chrome (Profiles -> Ghi Allocation Timeline -> Start) Tôi thấy sử dụng bộ nhớ sau sau khi nhấp vào nút một vài lần:

Memory consumption

Rõ ràng là bất kỳ bộ nhớ bị chiếm đóng bởi customDirective không bao giờ thực sự được phát hành, mặc dù chức năng $destroy của phạm vi đang được gọi.

Tôi đã sử dụng thành công $compile trước đây mà không tạo phạm vi mới, nhưng có vẻ như tôi thiếu một số thứ trong trường hợp này. Tôi có nên làm điều gì đó khác để đảm bảo rằng không có tham chiếu đến phạm vi mới?

Sửa

Dựa trên câu trả lời dưới đây bởi JoelCDoyle, đây là việc sửa chữa (tôi thêm một chức năng trên phá hủy đến phạm vi tôi tạo):

app.controller("mainCtrl", ["$scope", "$compile", function($scope, $compile) { 
    var childScope; 

    //call this every time the button is clicked 
    this.createDirective = function() { 
     //dynamically create a new instance of the custom directive 
     var customDirective = document.createElement("custom-directive"); 

     //if another child scope exists, destroy it 
     if (childScope) { 
      childScope.$destroy(); 
      childScope = undefined; 
     } 

     //create a new child scope 
     childScope = $scope.$new(); 

     //compile the custom directive 
     var compiledElement = $compile(customDirective)(childScope); 

     //FIX: remove the angular element 
     childScope.$on("$destroy", function() { 
      compiledElement.remove(); 
     }); 
    }; 
}]); 

Fixed fiddle

Trả lời

2

Tôi nghĩ rằng tôi đã tìm thấy một giải pháp cho điều này: https://jsfiddle.net/yqw1dk0w/8/

app.directive('customDirective', function(){ 
    return { 
    template: '<div ng-controller="customDirectiveCtrl"></div>', 
    link: function(scope, element) { 
     scope.$on('$destroy', function() { 
     element.remove(); 
     }); 
    } 
    }; 
}); 

tôi vẫn còn một chút mờ về lý do tại sao các công trình này, nhưng phần này, Làm thế nào Chỉ thị được biên soạn, trong tài liệu biên dịch góc cung cấp một đầu mối: https://docs.angularjs.org/guide/compiler

$ biên dịch mẫu có phạm vi bằng cách gọi hàm kết hợp kết hợp từ bước trước đó.Điều này lần lượt sẽ gọi chức năng liên kết các chỉ thị cá nhân, thính giả đăng ký trên các yếu tố và thiết lập $ watchs với phạm vi như mỗi chỉ thị được cấu hình để làm. \

Kết quả của việc này là một liên kết trực tiếp giữa phạm vi và DOM. Vì vậy, tại điểm này, một thay đổi trong một mô hình trên phạm vi biên dịch sẽ được phản ánh trong DOM.

Phá hủy phạm vi, tôi đoán, không loại bỏ những người nghe yếu tố này. Đó là những gì mã trên đang làm: destroy directive/child scope on scope destroy

+0

Điều này thực sự trông rất hứa hẹn vì nó sửa chữa ví dụ fiddle. Tôi sẽ áp dụng nó vào ứng dụng của tôi và xem nó có hoạt động ở đó không – kapoiosKapou

+1

Có! điều này cũng làm việc cho ứng dụng phức tạp hơn của tôi ..! Mặc dù .. Tôi vẫn không hiểu chính xác * tại sao * tác phẩm này hoạt động. Tôi không thêm nó vào DOM, vậy tại sao nó cần phải được loại bỏ? Ngoài ra, ngay cả khi tôi đã thêm phần tử đã biên dịch vào DOM và sau đó xóa nó, bộ nhớ vẫn bị rò rỉ. Có phải $ compile cũng đang thêm địa điểm này vào một nơi khác không? giống như một bộ nhớ cache ..? – kapoiosKapou

1

Nó sẽ bắt đầu deallocating nếu bạn đặt mảng phạm vi và de-phân bổ nó

$scope.array.length = 0; 

đến destcructor. Nhưng ... rất vui được biết. Tôi sẽ phải theo dõi mức tiêu thụ bộ nhớ chặt chẽ. Dường như phạm vi đó được giữ lại. Nguyên nhân tôi chỉ de-phân bổ các biến bên trong.

+0

'this.array' là không xác định bên trong trình lắng nghe hủy (đặt mảng bằng' var' thay vì 'this'), nhưng phương thức là âm thanh. Bộ sưu tập rác thu hồi bộ nhớ. Tốt đẹp! –

+0

ah ... đúng, tôi đã gán lại nó cho phạm vi để có thể giải quyết. chỉnh sửa ... –

+0

Đây chỉ là việc chăm sóc các triệu chứng, nó không thực sự khắc phục được sự cố. Mảng đó chỉ được cấp phát để mô phỏng bộ nhớ được sử dụng bởi một thành phần phức tạp hơn mà không thể tự xóa tất cả các biến mà nó đang sử dụng – kapoiosKapou

Các vấn đề liên quan