Knockout Performance
by bakhshi
HTML
<script src="//knockoutjs.com/downloads/knockout-3.3.0.js"></script>
<div class="container">
<div class="prefix"></div>
<div class="rows" data-bind="foreach:data.slice(index(), index() + count)">
<div class="row">
<span data-bind="text:name"></span>@
<date data-bind="text:Date()"></date>
</div>
</div>
<div class="postfix""></div>
</div>
CSS
.container {
border: solid 1px blue;
height: 500px;
overflow-y: auto;
}
.rows {
font-size:0;
}
.row {
font-size:14px;
}
date{
font-weight:bold;
}
JavaScript
var data = [];
var $ = document.querySelectorAll.bind(document);
var container = $('.container')[0];
for (var index = 0; index < 10000000; index++)
data.push({
name: 'reza ' + index
});
console.log(data.length);
const rowHeight = 25;
var model = {
data: ko.observableArray(data),
index: ko.observable(0),
postfixHeight: function () {
return rowHeight * (this.data().length - (this.index() + this.count)).toFixed() + 'px';
},
prefixHeight: function () {
var h = ( rowHeight * this.index()).toFixed() + 'px';
console.log(h);
return h;
},
count: 100
};
ko.applyBindings(model, container);
container.addEventListener('scroll', Throttle(function () {
const add = ((container.scrollTop / rowHeight) | 0);
console.log('rows: ', add);
model.index(Math.min(model.data().length - model.count, add));
$('.prefix')[0].style.height = model.prefixHeight();
$('.postfix')[0].style.height = model.postfixHeight();
}, 50));
function Throttle(fn, timeout) {
if (timeout === 0) return fn;
var result = function throttled() {
var _arguments = [].slice.call(arguments);
function CheckForNewCall() {
return !fn.__hasPendingCall;
}
function RescheduleCall() {
fn.__hasPendingCall = true;
fn.__lastArguments = _arguments;
fn.__pendingCall = setTimeout(function () {
var argArray = fn.__lastArguments.slice(0);
fn.__lastArguments = null;
fn.__hasPendingCall = false;
fn.apply(null, argArray);
}, timeout);
}
if (CheckForNewCall()) RescheduleCall();
else fn.__lastArguments = _arguments;
};
return result;
}