大量敲除嵌套可写计算的性能问题

时间:2014-05-16 20:09:47

标签: javascript knockout.js

我有一个淘汰赛应用程序,我有一个可写的可编程Observables层次结构,如下所示:

function InvoiceVM() {
   self.isSelected = ko.observable()
   self.selectedAmount = ko.computed(function() {
       if (self.isSelected())
            return self.usdBalance;
        else
            return 0;
   }
}
function CompanyVM() {
     self.invoices = ko.observableArray()
     self.totalSelectedAmount = ko.computed(function () {
        var total = 0;
        for (var i = 0; i < self.invoices().length; i++) {
            total += self.invoices()[i].selectedAmount();
        }
        return total;
    });

     self.isSelected = ko.computed({
        read: function () {
            var isSelected = true;
            for (var i = 0; i < self.invoices().length; i++) {
                if (!self.invoices()[i].isSelected())
                    isSelected = false;
            }
            return isSelected;
        },
        write: function (value) {
            for (var i = 0; i < self.invoices().length; i++)
                self.invoices()[i].isSelected(value);
        },
        deferEvaluation: true,
        owner: self
    })
}
function ParentVM() {
    self.companies = ko.observableArray()
    self.isSelected = ko.computed({
        read: function () {
            var isSelected = true;
            for (var i = 0; i < self.funds().length; i++) {
                if (!self.companies()[i].isSelected()) {
                    isSelected = false;
                    break;
                }
            }
            return isSelected;
        },
        write: function (value) {
            for (var i = 0; i < self.companies().length; i++) {
                var currentCompany = self.companies()[i];
                for (var j = 0; j < currentCompany.invoices().length; j++)
                    currentCompany.invoices()[j].isSelected(value);
            }

        },

        deferEvaluation: true
    });
}

问题是当选择了parentVM时(通过复选框),渲染所有复选框并更新总金额需要30-40秒。大约有4500个发票和大约274家公司(但只有公司正在展示,发票被隐藏使用display:none)。我已经尝试使用延迟更新插件限制可观察量,使用和不使用deferEvaluation选项,通过jQuery手动选择复选框(它没有使用2路绑定)。有没有人有关于加快这个过程的建议?在此先感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

我注意到了一些事情:

    在您对isSelected的写入中
  • ,因为您正在更新read函数的依赖关系的值,所以在更新每个isSelected时会反复触发计算。您可以使用限制器(或3.1中的rateLimit)扩展器来确保读取功能不会被调用。

  • read函数中,一旦找到错误值,就可以立即退出。在这种情况下,您不需要遍历所有值。

  • 每个totalSelectedAmount更新后,isSelected也会重新计算。对于throttle / rateLimit来说,这也是一个不错的选择。

尽管如此,同步更新仍然需要大量数据。可能值得为isSelected中的每个公司(或一大块公司)更新setTimeout,以确保在整个处理期间不冻结浏览器。

以下是包含许多此类更改的示例:http://jsfiddle.net/rniemeyer/k4vJ8/。我可能会考虑在每个setTimeout上更新一大块公司,而不是一次更新一个公司。

答案 1 :(得分:0)

加快速度的一种方法是在ko.observableArray的基础数组上运行操作。例如,您可以更改此

 for (var i = 0; i < self.invoices().length; i++)
       self.invoices()[i].isSelected(value);

到这个

 var underlying = self.invoices();
 for (var i = 0; i < underlying.length; i++)
       underlying[i].isSelected(value);

 self.invoices.valueHasMutated();

如果您的ko.observableArray包含许多元素(与您的元素相同),那么这样做肯定会为您带来显着的速度提升。您发布的代码中有多个位置可以实现此目的。有关详细信息,请参阅Knockout.js Performance Gotcha #2 - Manipulating observableArrays

答案 2 :(得分:0)

尝试在self.companies()

之外拨打self.companies()for ..等

observableArray()它是一个函数,当你调用observableArray()得到一个真实的对象时,你可以调用它一次。

看看