【问题标题】:Knockout components or templates performance gains淘汰赛组件或模板性能提升
【发布时间】:2015-10-29 21:50:06
【问题描述】:

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

var records = ko.observableArray([
  {
    p1: ko.observable("initProp1"),
    p2: ko.observable("initProp2"),
        // and so on
    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() 动态绑定 observables - 这可以提高性能吗?

我做了一些(简化的)测试,但我需要对问题进行一些跨浏览器的通用评估。根据我使用的浏览器甚至我的数据集,测试似乎不一致,而且无论如何都不能正确反映我所拥有的复杂性。直接在应用程序上进行测试意味着太多的工作,可能是无用的,这是我负担不起的,所以一般的指导原则对于在实际实施和测试中使用哪种解决方案至少有一个提示是很宝贵的。

【问题讨论】:

  • 您能提供一个带有示例的jsfiddle吗?你的场景似乎太复杂了。也许有更好的方法来实现这一点。
  • 小提琴链接:jsfiddle.net/2o4Lsq61/5

标签: jquery performance templates knockout.js components


【解决方案1】:

我制作了一个使用组件来提供输入字段的小提琴版本。使用的组件被命名为“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>

【讨论】:

    【解决方案2】:

    从您的 Fiddle 中,我看到您将每个字段呈现为单独的项目。如果每个项目都以相同的方式呈现,您可以绕过所有 if 绑定,作为自定义绑定文本项目,当单击该项目时,它会转换为其可编辑字段类型。

    如果您想保留制表符,可以输入默认演示文稿,但在获得焦点时,会显示相应的字段类型。

    更新:在我看来,您甚至可以让您的自定义绑定将适当的输入类型插入到绑定div 中,因此您的演示文稿将与它完全一样,但所有逻辑都在自定义绑定中。

    我制作了a Fiddle,它可以动态插入适当类型的输入。这有点粗糙,但给出了该方法的总体思路。我不知道这是否比if 绑定有性能优势;它可能只是以艰难的方式做同样的事情。当然,当用户想要编辑时,上述呈现为文本或简单输入并更改一个字段的建议在初始加载时会更快。

    【讨论】:

    • 我尝试了自定义绑定。通过使用 jQuery 动态创建项目,我将渲染时间减少了 80%。当然是一个很好的结果,使用适当的构建技术我可以获得更多,可能更喜欢innerHTML而不是jQuery,但结果已经非常好。然而,“模板”和“组件”呢?
    猜你喜欢
    • 1970-01-01
    • 2018-09-05
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    • 2016-02-27
    相关资源
    最近更新 更多