javascript – 如何清理KnockoutJS ViewModels?

前端之家收集整理的这篇文章主要介绍了javascript – 如何清理KnockoutJS ViewModels?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个单页应用程序,用户页面通过项目列表.每个项目依次有一个项目列表.

通过AJAX请求检索的服务器中的新项目更新了observable数组.这一切都很好.

不幸的是,几页之后,执行的操作次数(以及浏览器中使用的内存量,如FireFox和IE8)不断上升.我已经跟踪到这样一个事实,即我的observable数组中的元素没有被正确的清理,并且实际上仍然在内存中,尽管我已经用可观察的数组替换了新的数据.

我创建了一个small example,它复制了我看到的问题:

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);

If you look at the fiddle,您将注意到,“日志”包含每个viewmodel创建的条目.即使我预计这些项目中的每个项目都会很久,计算出的SubItem.computed属性即被运行.这在我的应用程序中的性能严重下降.

所以我的问题是:

>我在这里做错了什么?我期望KnockoutJS处理我实际需要手动处理的viewmodels吗?
>我使用ko.computed在SubItem导致问题?
>如果KnockoutJS不会处理这些视图模型,我该怎么处理它们?

更新:在进一步挖掘之后,我很确定SubItem中的计算属性是罪魁祸首.但是,我仍然不明白为什么这个财产仍在评估中.当可观察数组更新时,不应该损坏SubItem?

解决方法

一旦它的所有引用及其依赖项被删除,JavaScript垃圾回收器只能处理一个计算的可观察值.这是因为观测值保留对依赖于它们的任何计算的可观察值的引用(反之亦然).

一个解决方案是使计算的observable在不再具有任何依赖性时自行处理.这可以使用这样的帮助函数轻松完成.

function autoDisposeComputed(readFunc) {
    var computed = ko.computed({
        read: readFunc,deferEvaluation: true,disposeWhen: function() {
            return !computed.getSubscriptionsCount();
        }
    });
    return computed;
}
原文链接:https://www.f2er.com/js/152792.html

猜你在找的JavaScript相关文章