I work on a search page that allows filtering, searching and paginating through the list of results. Each time list of currently displayed items is changed, knockout takes a lot of time to render new values. My knockout knowledge is limited but I can see in the DevTools that things are being handled very inefficiently:
- item template is parsed for each element (no template caching?)
- each item is inserted into the DOM separately (no bulk operations?)
Do you have any suggestions for fixing these issues?
I tried to extract the relevant code:
$.get("/api/Search/GetSearchResults?page=" + bla)
.then(function (result) {
self.contentListViewModel.load(result.SearchHits);
//...
});
//----------------
var ContentListViewModel = function (options) {
self.searchHits = ko.observableArray([]);
//...
this.load = function (elements) {
for (var i = 0; i < elements.length; i++) {
elements[i] = new ContentElementViewModel(elements[i]);
//...
}
self.searchHits(elements);
}
}
//----------------
var ContentElementViewModel = function (dto, options) {
//just setting couple of observable variables and couple of methods
}
Relevant HTML:
<ul data-bind="foreach: { data: searchHits, afterRender: afterRenderSearchHits }, as: 'hit', masonry: { enable: true, hits: searchHits }, css: { 'listify': !pinterestEnabled() }">
<li data-bind="template: { name: $data.template() }"></li>
</ul>
The answer is to avoid using 'template' binding. It triggers multiple
jQuery.parseHTML
calls that are expensive.Slow code:
Fast code:
This response does not answer how to keep DOM manipulation to minimum, I'll ask another, more specific question for that.