large dataset with foreach

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.1.0.js"></script>
Load and DOM manipulation time: ~<span data-bind='text: finishTime() - startTime'></span> ms

<table>
<tbody class="ngTBody" data-bind="foreach: gridData">
<tr class="ngdatarow">
<td>
    <span class="nameHeader" data-bind="text: $data[$root.ColumnName()[0]], click: $root.gridNameClick" style="cursor: pointer; text-decoration: underline"></span>
</td>
<td>
    <span class="displayBlock" data-bind="text: $data[$root.ColumnName()[1]]"></span>
</td>
<td>
    <span class="displayBlock" data-bind="text: $data[$root.ColumnName()[2]]"></span>
</td>
</tr>
</tbody>
</table>

JavaScript

function ViewModel() {
    var self = this;
    self.ColumnName = ko.observableArray();
    self.gridData = ko.observableArray();
    self.totalRowCount = ko.observable();
    self.selectedItems = ko.observableArray();
    self.selectedRowCount = ko.observable();

    self.updateGrid = function (gridDataSource, groupGridOptions) {
        self.ColumnName(groupGridOptions.ColumnNameList);
        self.gridData(gridDataSource);
        self.totalRowCount(self.gridData().length);
        self.selectedItems.removeAll();
        self.selectedRowCount(0);
    };
    self.gridNameClick = function (item) {
        
    };
    self.startTime = new Date().getTime();
    self.finishTime = ko.observable(self.startTime);
}

var vm = new ViewModel();
ko.applyBindings(vm);

setTimeout(function () {
    vm.startTime = new Date().getTime();
    var options = {
        ColumnNameList: ['name','position','salary']
    };
    // Generate a random set of data
    var data = [];
    for (var i = 0; i < 5000; ++i) {
        var entry = {};
        entry.name = randomString(2);
        entry.position = randomString(2, 5);
        entry.salary = (Math.random() * 100000 + 50000).toFixed(2);
        data.push(entry);
    }
    vm.updateGrid(data, options);
    vm.finishTime(new Date().getTime());
}, 500);

var randomWords = ['Cras', 'placerat', 'orci', 'sit', 'amet', 'sagittis', 'aliquet', 'Etiam', 'non', 'feugiat', 'dui', 'Etiam', 'blandit', 'scelerisque', 'nibh', 'a', 'posuere', 'Aenean', 'euismod', 'sit', 'amet', 'mauris', 'non', 'pulvinar', 'Nulla', 'nulla', 'velit', 'tincidunt', 'sit', 'amet', 'mi', 'in', 'tincidunt', 'ultricies', 'ante', 'Nullam', 'fringilla', 'volutpat', 'urna', 'id', 'auctor', 'nunc', 'pharetra', 'nec', 'Vestibulum', 'est', 'ipsum', 'viverra', 'a', 'odio', 'vel', 'convallis', 'dictum', 'nunc', 'Mauris', 'placerat', 'dignissim', 'tempus', 'Praesent', 'bibendum', 'a', 'lorem', 'sollicitudin', 'fringilla', 'Nam', 'vel', 'massa', 'eget', 'libero', 'consectetur',...