敲除映射插件中的奇怪内存泄漏

Ily*_*nin 6 javascript knockout-mapping-plugin knockout.js

无法弄清楚为什么在使用knockout.mapping插件创建视图模型的情况下,处理计算的observable不会从全局变量中删除订阅.
首先让我们看看直接创建模型时会发生什么:

// 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());
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我使用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());
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

使用相同的技术记录堆分配,这是我看到的:

在此输入图像描述

我知道pureComputed,但是我想避免使用它们有两个原因:

  1. 切换到纯计算通过抛出异常来破坏遗留代码:

    '''pure'计算不能递归调用

解决这些问题需要花费很多时间.

  1. 更频繁地评估纯计算机,这会产生一些我想避免的性能开销,并且这再次影响遗留代码的不可预测性.

此外,我仍然希望使用映射插件,因为它能够监视集合状态(使用key映射属性),因为它为我创建了所有可观察对象.

那么有什么我错过了什么是在使用映射插件的情况下释放资源的正确方法是什么?

Chr*_*nty 5

深入研究映射插件,它会对计算机进行一些黑客攻击,并且在这种情况下显然会破坏它.

看起来设置你的计算价格deferEvaluation使得映射插件基本上不用考虑.

this.price = ko.computed(function () {
    // Computed is subscribed to global variable.
    return price + ' ' + Environment.currencyStr();
}, this, { deferEvaluation: true });
Run Code Online (Sandbox Code Playgroud)

  • 我认为我有一个主要想法 - 他们想为我的视图模型中找到的所有计算机创建代理(因为你提到的原因).因此,当我尝试处理我的计算机时,它并不重要,因为代理被处理而不是真正的计算(至少我认为是这样).但是当我们设置deferEvaluation:true时,它们不会创建代理,所以一切都按预期工作.谢谢,这是一个很好的调查! (2认同)