Knockout 组件或模板性能提升 [英] Knockout components or templates performance gains
问题描述
我有一个可观察的数组.对于每个数组元素,我生成了一些非常扩展的 html 表单,因为可观察的数组项是依次带有可观察的大对象:
var 记录 = ko.observableArray([{p1: ko.observable("initProp1"),p2: ko.observable("initProp2"),//等等pN: ko.observable("initPropN")},//...]);
html 可以很大、复杂和动态,根据自身的一些属性进行更改:为了实现这一点,我使用了 ko:if 绑定,众所周知,从计算上讲,这些绑定是很昂贵的(http://www.knockmeout.net/2012/03/knockoutjs-performance-gotcha-1ifwith.html),特别是对于有条件呈现的大 html.性能开始下降,尤其是在 IE 上.
注意到重复的(即使是动态的)结构,我正在考虑使用模板或组件,而不是直接在 html 中绑定数据.我会为每个动态配置使用不同的模板/组件.
一般来说,使用组件或模板可能会带来性能提升,还是在内部 Ko 与我不使用它们时完全一样?并且渲染模板和组件在性能上有区别吗?
否则,我正在考虑通过 JQuery 为每条记录生成 HTML,然后使用 ko.applyBindingsToNode() 动态绑定 observable - 这可以提供性能提升吗?
我做了一些(减少的)测试,但我需要对问题进行一些跨浏览器的通用评估.根据我使用的浏览器甚至我的数据集,测试似乎不一致,无论如何都不能正确反映我的复杂性.直接在应用程序上进行测试将意味着太多的工作,可能毫无用处,这是我负担不起的,因此,至少有一个关于用于实际实施和测试的解决方案的提示的通用指南将非常宝贵.
我制作了您的小提琴的一个版本,它使用组件来提供输入字段.使用的组件命名为my-"加上 type
字段(这是区分我的组件与 input
和 select
标签所必需的).我不知道这会有多好,但它很简单,你应该可以做一些测试看看.
ko.components.register('my-input', {视图模型:输入模型,模板: {元素:'输入模板'}});ko.components.register('我的选择', {视图模型:输入模型,模板: {元素:'选择模板'}});ko.components.register('my-mu', {视图模型:输入模型,模板: {元素:'mu-模板'}});函数输入模型(参数){返回参数;}函数模型(){记录 = ko.observableArray([[{类型:输入",id: "日期",尺寸:100px",值:ko.observable()}, {类型:选择",id: "天气",尺寸:100px",值:ko.observable(),选项: [{optId: "w1",optTxt:阴天"}, {optId: "w2",optTxt: "阳光明媚"}, {optId: "w3",optTxt: "下雨"}, {optId: "w4",optTxt: "下雪"}, {optId: "w5",optTxt:有雾"}]}, {类型:输入",id: "纬度",尺寸:80px",值:ko.observable()}, {类型:输入",id: "长",尺寸:80px",值:ko.observable()}],[{类型:输入",id: "日期",尺寸:100px",值:ko.observable()}, {类型:选择",id: "温度",尺寸:120px",值:ko.observable(),选项: [{optId: "t0",选项文本:<-10"}, {optId: "t1",optTxt: "]-10 : 0]"}, {optId: "t2",optTxt: "]0 : 20]"}, {optId: "t3",optTxt: "]20 : 40]"}, {optId: "t4",选项文本:> 40"}]}, {类型:选择",id: "风",尺寸:70px",值:ko.observable(),选项: [{optId: "wind1",optTxt:强"}, {optId: "wind2",optTxt:弱"}]}],[{类型:输入",id: "日期",尺寸:100px",值:ko.observable()}, {类型:选择",id: "天气",尺寸:100px",值:ko.observable(),选项: [{optId: "w1",optTxt:阴天"}, {optId: "w2",optTxt: "阳光明媚"}, {optId: "w3",optTxt: "下雨"}, {optId: "w4",optTxt: "下雪"}, {optId: "w5",optTxt:有雾"}]}, {类型:输入",id: "纬度",尺寸:80px",值:ko.observable()}, {类型:输入",id: "长",尺寸:80px",值:ko.observable()}],[{类型:输入",id: "日期",尺寸:100px",值:ko.observable()}, {类型:选择",id: "温度",尺寸:120px",值:ko.observable(),选项: [{optId: "t0",选项文本:<-10"}, {optId: "t1",optTxt: "]-10 : 0]"}, {optId: "t2",optTxt: "]0 : 20]"}, {optId: "t3",optTxt: "]20 : 40]"}, {optId: "t4",选项文本:> 40"}]}, {类型:输入",id: "湿度",尺寸:70px",值:ko.observable(),选项: [{optId: "wind1",optTxt:强"}, {optId: "wind2",optTxt:弱"}]}, {类型:亩",id:空,价值: '%'}]]);}var myModel = new Model();ko.applyBindings(myModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script><模板 id="选择模板"><select data-bind="style: {width: size}, value: value, options: options, optionsText: 'optTxt', optionsValue: 'optId'"></select>模板><模板id="输入模板"><input type="text" data-bind="style: {width: size}, value: value"/>模板><模板id="mu-template"><span data-bind="text: value"></span>模板><div data-bind="foreach:记录"><div data-bind="foreach: $data"><label data-bind="text: id"></label><!-- ko component:{name:'my-'+type, params:$data} --><!--/ko -->
I have an observable array. For every array element I generate some html form, very extended, as the observable array items are large objects with observables in turn:
var records = ko.observableArray([
{
p1: ko.observable("initProp1"),
p2: ko.observable("initProp2"),
// and so on
pN: ko.observable("initPropN")
},
//...
]);
The html can be large, complex and dynamic, changing on the basis of some of the properties themselves: to achieve this I make use of ko:if bindings, which are known to be expensive computationally speaking (http://www.knockmeout.net/2012/03/knockoutjs-performance-gotcha-1ifwith.html), especially for large html conditionally rendered. Performance is starting suffering, especially on IEs.
Noted the repetitive, even if dynamic, structure, I am thinking about use templates or components intead of binding data directly in the html. I would use different templates/components for each dynamic configuration.
Generally speaking, can be possible that using components, or templates, will give a performance gain, or internally Ko does exactly as I would do without using them? And there is difference in performance between rendering templates and components?
Otherwise, I am considering generating HTML via JQuery every record, and then dynamically bind observables with ko.applyBindingsToNode() - could this provide performance gains?
I did some (reduced) tests, but I need some cross-browser generic evaluation of the problem. Tests seem to be discordant depending on which browser I use and even on my dataSet, and anyway do not reflect properly the complexity I have. Testing directly on the application would mean too much work, possibly useless, which I can't afford, so general guidelines would be precious to have at least an hint on which solution to use for real-life implementation and test.
I made a version of your fiddle that uses components to supply the input fields. The component used is named 'my-' plus whatever the type
field is (this was necessary to distinguish my components from input
and select
tags). I don't know how well this will perform, but it's simple enough that you should be able to do some testing and see.
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>
这篇关于Knockout 组件或模板性能提升的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!