【问题标题】:Performance issue with lots of knockout nested writeable computeds大量淘汰嵌套可写计算的性能问题
【发布时间】:2014-05-17 05:32:31
【问题描述】:

我有一个淘汰应用程序,其中有一个可写计算 Observable 的层次结构,如下所示:

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
    });
}

问题在于,当父VM 被选中时(通过复选框),渲染所有复选框并更新总金额需要 30-40 秒。大约有 4500 张发票和大约 274 家公司(但仅显示公司,使用 display:none 隐藏发票)。我尝试使用延迟更新插件(无论是否使用 deferEvaluation 选项)限制可观察对象的速率,通过 jQuery 手动选择复选框(这不适用于 2 路绑定)。有人对加快这个过程有什么建议吗?提前感谢您的帮助!

【问题讨论】:

  • 考虑切换模板引擎。
  • 另外,您可以修改底层数组和批量更改,然后在有帮助的情况下手动通知更改。
  • 你推荐什么模板引擎?
  • 这是个人喜好问题,起初,我会完全使用一些非常基本的东西(只是转储字符串),然后看看它是否会有所作为。

标签: javascript knockout.js


【解决方案1】:

我注意到了一些事情:

  • 在您对isSelected 的写入中,由于您正在更新与read 函数相关的值,因此您在更新每个isSelected 时会一遍又一遍地触发计算。您可以使用油门(或 3.1 中的 rateLimit)扩展程序来确保不会继续调用读取函数。

  • 在您的read 函数中,您可以真正在发现错误值时立即退出。在这种情况下,您不需要遍历所有值。

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

话虽如此,同步更新的数据仍然很多。可能值得为setTimeout 中的每个公司(或一大块公司)更新isSelected,以确保浏览器在整个处理过程中不会被冻结。

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

【讨论】:

  • 感谢您的帮助!批量更新对我有用。
【解决方案2】:

尝试在for之外拨打self.companies()self.companies()..等

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

看看

【讨论】:

    【解决方案3】:

    加快速度的一种方法是在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 了解更多信息。

    【讨论】:

      猜你喜欢
      • 2015-06-02
      • 2014-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-03
      • 1970-01-01
      • 2013-12-04
      相关资源
      最近更新 更多