无法弄清楚为什么在使用knockout.mapping插件创建视图模型的情况下,处理计算的observables不会从全局变量中删除订阅。
首先让我们看看直接创建模型时会发生什么:
// Global variable.
var Environment = {
currencyStr: ko.observable("usd.")
};
// Item model, used intensively.
function ItemModel(price) {
var self = this;
this.price = ko.computed(function () {
// Computed is subscribed to global variable.
return price + ' ' + Environment.currencyStr();
});
};
ItemModel.prototype.dispose = function () {
// Dispoing subscription to global variable.
this.price.dispose();
};
function ViewModel() {
var self = this;
self.items = ko.observableArray([]);
// Simply adds 1000 new items to observable array directly.
self.addItems = function () {
for (var i = 0; i < 1000; i++) {
self.items.push(new ItemModel(i));
}
};
// Disposes and removes items from observable array
this.removeItems = function () {
ko.utils.arrayForEach(self.items(), function (item) {
item.dispose();
});
self.items.removeAll();
};
};
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<button data-bind="click: addItems">Add items</button>
<button data-bind="click: removeItems">Remove items</button>
<div data-bind="foreach: items">
<div>
<span data-bind="text: price"></span>
</div>
</div>
我使用Chrome开发工具记录堆分配,同时多次添加和删除项目。每次添加后,先前分配的对象都已成功清理,我得到以下图片:
现在使用映射插件的功能相同:
// Global variable.
var Environment = {
currencyStr: ko.observable("usd.")
};
// Item model, used intensively.
function ItemModel(price) {
var self = this;
this.price = ko.computed(function () {
// Computed is subscribed to global variable.
return price + ' ' + Environment.currencyStr();
});
};
ItemModel.prototype.dispose = function () {
// Dispoing subscription to global variable.
this.price.dispose();
};
function ViewModel() {
var self = this;
self.items = ko.observableArray([]);
self.itemsMapping = {
'create': function (options) {
return new ItemModel(options.data);
}
};
// Simply adds 1000 new items to observable array using mapping plugin.
self.addItems = function () {
var itemsPrices = new Array(1000);
for (var i = 0; i < 1000; i++) {
itemsPrices[i] = i;
}
// Mapping new array to our observable array.
ko.mapping.fromJS(itemsPrices, self.itemsMapping, self.items);
};
// Disposes and removes items from observable array
this.removeItems = function () {
ko.utils.arrayForEach(self.items(), function (item) {
item.dispose();
});
self.items.removeAll();
};
};
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<button data-bind="click: addItems">Add items</button>
<button data-bind="click: removeItems">Remove items</button>
<div data-bind="foreach: items">
<div>
<span data-bind="text: price"></span>
</div>
</div>
使用相同的技术记录堆分配,这就是我所看到的:
我知道pureComputed,但我希望避免使用它们有两个原因:
''''pure'计算不能递归调用
解决这些问题需要花费很多时间。
此外,我仍然希望使用映射插件,因为它能够监视集合状态(使用key
映射属性),因为它为我创建了所有可观察对象。
那么我是否遗漏了一些东西,以及在使用映射插件时释放资源的正确方法是什么?
答案 0 :(得分:5)
深入研究映射插件,它对计算机进行了一些黑客攻击,并且在这种情况下显然会破坏它。
将计算出的价格设置为deferEvaluation
似乎会使映射插件在很大程度上不受影响。
this.price = ko.computed(function () {
// Computed is subscribed to global variable.
return price + ' ' + Environment.currencyStr();
}, this, { deferEvaluation: true });