淘汰组件或模板性能提升

时间:2015-08-06 16:21:44

标签: jquery performance templates knockout.js components

我有一个可观察的数组。对于每个数组元素,我生成一些非常扩展的html表单,因为可观察的数组项是依次具有observable的大对象:

var records = ko.observableArray([
  {
    p1: ko.observable("initProp1"),
    p2: ko.observable("initProp2"),
        // and so on
    pN: ko.observable("initPropN")
  },
  //...
]);

html可以是大型的,复杂的和动态的,在某些属性本身的基础上进行更改:为了实现这一点,我使用了ko:if bindings,已知计算代价高昂http://www.knockmeout.net/2012/03/knockoutjs-performance-gotcha-1ifwith.html ),特别是对于有条件渲染的大型HTML。性能开始受到影响,特别是在IE上。

注意到重复的,即使是动态的结构,我正在考虑直接在html中使用模板或组件intead绑定数据。我会为每个动态配置使用不同的模板/组件。

一般来说,使用组件或模板可能会带来性能提升,或者内部Ko可以完全按照我不使用它的方式做到吗?渲染模板和组件之间的性能存在差异吗?

否则,我正在考虑通过JQuery每条记录生成HTML,然后使用ko.applyBindingsToNode()动态绑定observables - 这可以提供性能提升吗?

我做了一些(减少的)测试,但我需要对问题进行一些跨浏览器的通用评估。测试似乎不一致取决于我使用的浏览器甚至是我的数据集,并且无论如何都没有正确反映我的复杂性。直接在应用程序上进行测试意味着太多的工作,可能是无用的,我无法负担,所以一般的指导方针对于至少提供一个用于现实生成和测试的解决方案的提示是很宝贵的。

2 个答案:

答案 0 :(得分:2)

我制作了一个使用组件来提供输入字段的小提琴版本。使用的组件名为“my-”加上type字段的任何内容(这是区分我的组件与inputselect标记所必需的)。我不知道这会有多好,但它很简单,你应该能够进行一些测试并看到。

ko.components.register('my-input', {
  viewModel: InputModel,
  template: {
    element: 'input-template'
  }
});
ko.components.register('my-select', {
  viewModel: InputModel,
  template: {
    element: 'select-template'
  }
});
ko.components.register('my-mu', {
  viewModel: InputModel,
  template: {
    element: 'mu-template'
  }
});

function InputModel(params) {
  return params;
}


function Model() {
  records = ko.observableArray([
    [{
      type: "input",
      id: "Date",
      size: "100px",
      value: ko.observable()
    }, {
      type: "select",
      id: "Weather",
      size: "100px",
      value: ko.observable(),
      options: [{
        optId: "w1",
        optTxt: "Cloudy"
      }, {
        optId: "w2",
        optTxt: "Sunny"
      }, {
        optId: "w3",
        optTxt: "Rainy"
      }, {
        optId: "w4",
        optTxt: "Snowy"
      }, {
        optId: "w5",
        optTxt: "Foggy"
      }]
    }, {
      type: "input",
      id: "Lat",
      size: "80px",
      value: ko.observable()
    }, {
      type: "input",
      id: "Long",
      size: "80px",
      value: ko.observable()
    }],
    [{
      type: "input",
      id: "Date",
      size: "100px",
      value: ko.observable()
    }, {
      type: "select",
      id: "Temperature",
      size: "120px",
      value: ko.observable(),
      options: [{
        optId: "t0",
        optTxt: "<-10"
      }, {
        optId: "t1",
        optTxt: "]-10 : 0]"
      }, {
        optId: "t2",
        optTxt: "]0 : 20]"
      }, {
        optId: "t3",
        optTxt: "]20 : 40]"
      }, {
        optId: "t4",
        optTxt: ">40"
      }]
    }, {
      type: "select",
      id: "Wind",
      size: "70px",
      value: ko.observable(),
      options: [{
        optId: "wind1",
        optTxt: "Strong"
      }, {
        optId: "wind2",
        optTxt: "Weak"
      }]
    }],
    [{
      type: "input",
      id: "Date",
      size: "100px",
      value: ko.observable()
    }, {
      type: "select",
      id: "Weather",
      size: "100px",
      value: ko.observable(),
      options: [{
        optId: "w1",
        optTxt: "Cloudy"
      }, {
        optId: "w2",
        optTxt: "Sunny"
      }, {
        optId: "w3",
        optTxt: "Rainy"
      }, {
        optId: "w4",
        optTxt: "Snowy"
      }, {
        optId: "w5",
        optTxt: "Foggy"
      }]
    }, {
      type: "input",
      id: "Lat",
      size: "80px",
      value: ko.observable()
    }, {
      type: "input",
      id: "Long",
      size: "80px",
      value: ko.observable()
    }],
    [{
        type: "input",
        id: "Date",
        size: "100px",
        value: ko.observable()
      }, {
        type: "select",
        id: "Temperature",
        size: "120px",
        value: ko.observable(),
        options: [{
          optId: "t0",
          optTxt: "<-10"
        }, {
          optId: "t1",
          optTxt: "]-10 : 0]"
        }, {
          optId: "t2",
          optTxt: "]0 : 20]"
        }, {
          optId: "t3",
          optTxt: "]20 : 40]"
        }, {
          optId: "t4",
          optTxt: ">40"
        }]
      }, {
        type: "input",
        id: "Humidity",
        size: "70px",
        value: ko.observable(),
        options: [{
          optId: "wind1",
          optTxt: "Strong"
        }, {
          optId: "wind2",
          optTxt: "Weak"
        }]
      }, {
        type: "mu",
        id: null,
        value: '%'
      }

    ]
  ]);

}
var myModel = new Model();
ko.applyBindings(myModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<template id="select-template">
  <select data-bind="style: {width: size}, value: value, options: options, optionsText: 'optTxt', optionsValue: 'optId'"></select>
</template>
<template id="input-template">
  <input type="text" data-bind="style: {width: size}, value: value" />
</template>
<template id="mu-template"> <span data-bind="text: value"></span>

</template>
<div data-bind="foreach: records">
  <div data-bind="foreach: $data">
    <label data-bind="text: id"></label>
    <!-- ko component:{name:'my-'+type, params:$data} -->
    <!-- /ko -->
  </div>
</div>

答案 1 :(得分:1)

从您的小提琴中,我看到您将每个字段渲染为单个项目。如果每个项目的显示方式相同,则可以绕过所有if绑定,作为自定义绑定的文本项,单击该项后,将转换为其可编辑的字段类型。

如果要保留标签,可以输入默认演示文稿,但在焦点时,会显示相应的字段类型。

更新:我发现你甚至可以让自定义绑定将相应的输入类型插入到绑定的div中,因此你的演示文稿将完全如此,但所有逻辑都在自定义绑定中。

我已经a Fiddle动态插入了适当类型的输入。它有点粗糙,但给出了方法的一般概念。我不知道它是否比if绑定更具性能优势;它可能只是在艰难的方式做同样的事情。当然,上面提到的渲染为文本或简单输入并在用户想要编辑时更改一个字段的建议在初始加载时会更快。