3
votes

In the simple example below, Knockout calls HTMLElement.appendChild 18 times to render the template. It doesn't use DocumentFragment, so each of these 18 operations are made on the live DOM causing reflows. Ideally, there should be only one call to appendChild on the live DOM.

This really hurts performance, does anyone know how to reduce the damage?


JS BIN with the code.


JavaScript

var viewModel = {
  people:[
    {name: 'Tim'},
    {name: 'John'},
    {name: 'Greg'}
  ]
};

ko.applyBindings(viewModel, document.getElementById('list1'));

HTML

<ul id='list1' data-bind="foreach: { data: people }">
  <li>
      <h3 data-bind="text: name"></h3>
  </li>
</ul>
1
Didn't check the code above the ** KO ** part but here's the AngularJS version jsbin.com/lizi/4 - Philipp Gayret
you can hide during updates to prevent re-layout... - dandavis
@user1066946 Nice! Unfortunately, I'm working on an existing app and I'm not in position to change the framework/library right now. - Konrad Dzwinel
There are before and after rendering callbacks for KO templates. - rwisch45
If you remove the line breaks around the li it will not have to deal with those text nodes (so <ul><li></li></ul>). That brings it down to 10. The 1st one is actually copying the original li to a new div as part of storing it, so not appending to the document. The last 3 are unrelated to KO (just part of loading jQuery). So, there are only 6 (adding 3 lis and 3 text nodes for text binding. - RP Niemeyer

1 Answers

3
votes

My Repeat plugin provides a binding that can be used as an alternative to the foreach binding. It's faster in many cases, so you'll just need to experiment to compare the performance.

For comparison, here's how you'd bind your example using repeat:

<ul id='list1'>
  <li data-bind="repeat: people">
    <h3 data-bind="text: $item().name"></h3>
  </li>
</ul>

http://jsbin.com/lizi/7/edit