内存泄漏与observableArray和foreach绑定

时间:2014-01-09 11:52:15

标签: javascript knockout.js memory-leaks ko.observablearray

我们有一个SPA,可以通过AJAX获取小批量的项目,并使用它们来填充通过foreach绑定到DOM的淘汰赛observableArray。

当新数据到达时,我们使用removeAll()清除旧数组并推送新项目。使用Chrome配置文件工具,我们发现这会导致内存泄漏,并且数据和闭包的数量会悬空。泄漏越多,泄漏越大。

我们构建了一个简单的测试用例来演示该问题(请参阅此fiddle)。重现:

  • 使用Chrome,打开开发工具面板,然后选择“个人资料”> 'Record Heap Allocations'
  • 点击一次以获取一些数据
  • 启动探查器并拍摄快照
  • 点击很多次
  • 拍摄另一张快照并与第一张
  • 进行比较

HTML:

<div data-bind="click:go,
    text:(clickCount()==0)
           ? 'click once then take a heap snapshot'
           : 'click me lots then take another heap snapshot to compare'"
     style="cursor:pointer"></div>

<ul data-bind="foreach:array">
    <div data-bind="text:$data.name"></div>
    <div data-bind="text:$data.age"></div>
</ul>

使用Javascript:

var getJoes = function(){
    var joes=[];
    for(var i=0;i<10;i++)
    {
        var name="Joe";
        var age=((Math.random()*10)+1)>>0;
        joes.push({Name:name,Age:age});
    }
    return joes;
};
function viewModel(){
    var self=this;
    self.array = ko.observableArray();
    self.clickCount=ko.observable(0);
    self.go = function(){
        self.clickCount(self.clickCount()+1);
        self.array.removeAll();
        var joes=getJoes();
        joes.forEach(function(joe){
                var joeObs = ko.observable({
                    name:ko.observable(joe.Name),
                    age:ko.observable(joe.Age)});
                self.array.push(joeObs);
            });

    };         
}
ko.applyBindings(new viewModel());

这是一个错误还是我们遗漏了什么?

2 个答案:

答案 0 :(得分:1)

我正在弄乱你的小提琴,并注意到如果你推动具有可观察属性的vanilla对象而不是推动包裹在一个observable中的vanilla对象,问题就会消失:

    joes.forEach(function(joe){
            var joeObs = {
                name:ko.observable(joe.Name),
                age:ko.observable(joe.Age)};
            self.array.push(joeObs);
        });

我对此没有任何解释。所以我的答案更多的是一个问题......真正的区别是什么?为什么一个泄漏而另一个没有?

答案 1 :(得分:1)

我们从jsfiddle中取出测试用例,独立运行和宾果游戏 - 没有内存泄漏。呼。

似乎它比预期更多地参与舞蹈!