当我在viewModel中有一个大型数据集时,我使用foreach
循环一个对象数组来将每个Object渲染为一个表中的一行,KnockoutJS将阻塞主线程直到它可以渲染,有时需要几分钟(!)。
这是一个使用包含2000个对象的数据集的jsFiddle示例,其中包含url
和code
。在某些情况下,真实数据会有更长的URL和其他4列(本例中只有2个。)我还添加了一些简单的样式,因为在此过程中添加样式似乎也会使事情变慢。
警告:您的浏览器可能中断
答案 0 :(得分:1)
我建议如果你有这么大的数据集,你可以尝试另一种解决方案。例如,slickGrid通过仅为实际可见的数据生成HTML元素,以更有效的方式呈现大型数据集。我们已经将它用于大型数据集,并且表现良好。
答案 1 :(得分:1)
这样的事情怎么样?说,你有viewModel.items = ko.observableArray()
你想要渲染。
var itemsToRender = functionThatReturnsLargeArray()
。itemsToRender
中的部分数据放入可观察数组中。比如,只有50个元素。setTimeout
回调中的部分中将元素添加到可观察数组中。 注意1:您可以在setTimeout
回调中添加一些时间跟踪,并增加/减少每次迭代时添加的项目数。您的目标是将每个回调时间保持在50-100毫秒以下,以便您的应用程序仍能感受到响应。
var batchSize = 50; // default number of items rendered per iteration
var batchOffset = 0;
function render(items, itemsToRender, done) {
setTimeout(function () {
var startTime = new Date().getTime();
items.pushAll(itemsToRender.slice(batchOffset, batchSize));
batchOffset += batchSize;
// at this point Knockout rendered next batchSize items from itemsToRender
var endTime = new Date().getTime();
// update batchSize for next iteration
batchSize = batchSize * 50 / (endTime - startTime); // 50 milliseconds
batchSize = Math.min(itemsToRender.length, batchOffset + batchSize);
if (batchSize > 0) render() else done(); // callback if you need one
}, 0);
}
/* I haven't actually tested the code */
另一种批量更新策略可以基于目标FPS。假设您希望达到60 fps的更新速率,因此每1000毫秒可以调用setTimeout
60次。处理整个集合需要更长的时间。您也可以使用requestAnimationFrame
代替setTimeout
,看看它会如何解决。
编辑:Build-in throttling已添加到Knockout JS 1.3(目前处于测试阶段,但似乎相当稳定)。
注2:如果视图上的其他一些数据取决于viewModel.items
,您仍然可以将其映射到原始数组itemsToRender
。比如说,您想要显示集合中的项目数。如果您使用viewModel.items().length
,您最终会在UI中更改大小值,而更多项目会被渲染。为避免这种情况,您可以先根据dependentObservable
将大小绑定定义为itemsToRender
,而不是viewModel.items
。完成所有项目的渲染后,如果您认为合适,可以将其重新映射到viewModel.items
。