Jak mam oczyścić KnockoutJS ViewModels?

Mam aplikację na jedną stronę, w której użytkownik przegląda listy elementów. Każdy przedmiot z kolei ma listę przedmiotów.

Tablica obserwowalna jest aktualizowana o nowe elementy z serwera pobranego przez żądanie AJAX. To wszystko działa dobrze.

Niestety po kilku stronach liczba wykonywanych operacji (i ilość pamięci używanej w przeglądarkach takich jak FireFox i IE8) stale rośnie. Sprawdziłem, że elementy w mojej obserwowalnej tablicy nie są prawidłowo czyszczone i są nadal w pamięci, mimo że zastąpiłem elementy w mojej obserwowalnej tablicy nowymi danymi.

Stworzyłemmały przykład replikuje problem, który widzę:

HTML:

<p data-bind="text: timesComputed"></p>
<button data-bind="click: more">MORE</button>
<ul data-bind="template: { name: 'items-template', foreach: items }">
</ul>

<script id="items-template">
    <li>
        <p data-bind="text: text"></p>
        <ul data-bind="template: { name: 'subitems-template', foreach: subItems }"></ul>
    </li>
</script>

<script id="subitems-template">
    <li>
        <p data-bind="text: text"></p>
    </li>
</script>

JavaScript / KnockoutJS ViewModels:

var subItemIndex = 0;

$("#clear").on("click", function () {
  $("#log").empty();
});

function log(msg) {
  $("#log").text(function (_, current) {
    return current + "\n" + msg;
  });
}
function Item(num, root) {
  var idx = 0;

  this.text = ko.observable("Item " + num);
  this.subItems = ko.observableArray([]);
  this.addSubItem = function () {
    this.subItems.push(new SubItem(++subItemIndex, root));
  }.bind(this);

  this.addSubItem();
  this.addSubItem();
  this.addSubItem();
}

function SubItem(num, root) {
  this.text = ko.observable("SubItem " + num);
  this.computed = ko.computed(function () {
    log("computing for " + this.text());
    return root.text();
  }, this);

  this.computed.subscribe(function () {
    root.timesComputed(root.timesComputed() + 1);
  }, this);
}

function Root() {
  var i = 0;

  this.items = ko.observableArray([]);
  this.addItem = function () {
    this.items.push(new Item(++i, this));
  }.bind(this);

  this.text = ko.observable("More clicked: ");
  this.timesComputed = ko.observable(0);

  this.more = function () {
    this.items.removeAll();
    this.addItem();
    this.addItem();
    this.addItem();    
    this.timesComputed(0);
    this.text("More clicked " + i);
  }.bind(this);

  this.more();
}

var vm = new Root();

ko.applyBindings(vm);

Jeśli spojrzysz na skrzypce, zauważysz, że „dziennik” zawiera wpis dlakażdy stworzony ViewModel. obliczona właściwośćSubItem.computed jest uruchamiany nawet po tym, jak spodziewałem się, że każdy z tych przedmiotów zniknie. Powoduje to poważną degradację wydajności w mojej aplikacji.

Więc moje pytania są:

Co ja tu robię źle? Czy oczekuję, że KnockoutJS usunie ViewModels, które faktycznie muszę usuwać ręcznie?Czy moje wykorzystanieko.computed naSubItem powoduje problem?Jeśli KnockoutJS nie zamierza pozbyć się tych viewmodeli, jak mam się ich pozbyć?

Aktualizacja: Po dalszych kopaniach jestem pewien, że obliczona właściwość wSubItem jest winowajcą. Nadal jednak nie rozumiem, dlaczego ta właściwość jest nadal oceniana. Nie powinienemSubItem zostać zniszczone, gdy tablica obserwowalna zostanie zaktualizowana?

questionAnswers(1)

yourAnswerToTheQuestion