谁将处理即时创建的计算机?

时间:2014-12-18 09:50:08

标签: javascript knockout.js

我使用knockout.js构建SPA。在我的视图模型中,我经常使用"在飞行中"计算跟踪变化和维持状态的技巧。这是一个例子:

var fileBrowserViewModel = function() {
  this.currentFolder = ko.observable("/");
  this.folderPath = ko.observableArray(["/"]);

  // on-the-fly created computed to maintain folderpath when currentFolder changes
  ko.computed(function() {
    var index = this.folderPath.indexOf(this.currentFolder());
    if (index < 0)
      this.folderPath.push(this.currentFolder());
    else
      this.folderPath.splice(index+1, this.folderPath().length-index);
  }, this);     
}

我有一个逻辑,它处理viewmodel的每个公开公开的计算属性。但是,在发布包装视图模型后,这些隐式声明的计算结果会发生什么? 处理计算的方式和时间?它会导致内存泄漏吗?

1 个答案:

答案 0 :(得分:4)

如何以及何时处理完毕的计算?

从某种意义上说,他们的.dispose函数从未被调用过。

会导致内存泄漏吗?

也许,但并非总是如此。计算需要.dispose'd的原因是因为他们对依赖项进行了订阅;这意味着每个依赖项都持有对计算的引用。当不再有任何引用时,计算将收集垃圾。在上面的示例中,当ViewModel本身不再在任何地方引用时会发生这种情况,因此计算的内容将按照预期与其ViewModel一起收集垃圾。

但是,如果计算取决于包含它的ViewModel之外的任何内容,则它将不会被垃圾收集,直到它所依赖的所有内容本身都准备好被垃圾收集。在最坏的情况下,计算依赖于从不垃圾收集的全局,计算机本身永远不会被垃圾收集。

因此,真正的答案是,只有需要才能处理计算机,因为它具有比计算本身更长寿命的依赖项。但是,由于处理一个无论如何都会收集垃圾的计算机没有什么害处,因此通常更容易确保ViewModel创建的所有计算机都被处理掉了;而不是试图分开哪些需要处理。

如何处理计算处置

在任何情况下,您都希望在viewModel或某些等效方法上使用.dispose方法。一些外部逻辑无法知道私有创建的计算机,因此ViewModel本身需要自己处理它。处理此问题的简单方法是在VM的.dispose方法中为每个私有创建的计算机调用.dispose

var fileBrowserViewModel = function() {
    // on-the-fly created computed to maintain folderpath when currentFolder changes
    var folderPathComputed = ko.computed(function() {
        //implementation omitted
    }, this);     

    this.dispose = function () {
        folderPathComputed.dispose();
    }
}

如果你想减少手动;您可以创建一个实用程序来处理您的处理,例如:

function ComputedManager() {
    var computedsToDispose = [];

    this.computed = function() {
        //create a computed normally, with the provided arguments
        var computed = ko.computed.apply(ko, arguments);
        computedsToDispose.push(computed);
        return computed;
    }

    this.dispose = function() {
        computedsToDispose.forEach(function(computed) {
            computed.dispose();
        });
    }
}

var fileBrowserViewModel = function() {
    var computedManager = new ComputedManager();

    // on-the-fly created computed to maintain folderpath when currentFolder changes
    computedManager.computed(function() {
        //implementation omitted
    }, this);     

    this.dispose = computedManager.dispose;
}

总是调用computedManager.computed而不是ko.computed有点尴尬,但它比手动清理每个计算器更容易,并且好处是你可以用这种方式创建所有计算,然后消除了对其他逻辑的需要,以及查找和处理所有公开暴露的计算。