Javascript knockoutjsforeach阻塞主线程
当我的viewModel中有一个大数据集,并且我使用Javascript knockoutjsforeach阻塞主线程,javascript,knockout.js,Javascript,Knockout.js,当我的viewModel中有一个大数据集,并且我使用foreach在对象数组上循环以将每个对象渲染为表中的一行时,KnockoutJS将阻塞主线程,直到它可以渲染为止,这有时需要几分钟(!) 下面是一个使用包含2000个对象的数据集的JSFIDLE示例,其中包含url和code。在某些情况下,真实数据将有更长的URL和其他4列(在本例中只有2列)。我还添加了一些简单的样式,因为添加样式似乎也会在过程中减慢速度 警告:您的浏览器可能会损坏 我建议,如果您有如此大的数据集,请尝试其他解决方案。例如,
foreach
在对象数组上循环以将每个对象渲染为表中的一行时,KnockoutJS将阻塞主线程,直到它可以渲染为止,这有时需要几分钟(!)
下面是一个使用包含2000个对象的数据集的JSFIDLE示例,其中包含url
和code
。在某些情况下,真实数据将有更长的URL和其他4列(在本例中只有2列)。我还添加了一些简单的样式,因为添加样式似乎也会在过程中减慢速度
警告:您的浏览器可能会损坏
我建议,如果您有如此大的数据集,请尝试其他解决方案。例如,通过仅为实际可见的数据生成HTML元素,以更高效的方式呈现大型数据集。我们已经将其用于大型数据集,并且它的性能很好。类似的东西怎么样。比如说,您已经有了想要渲染的
viewModel.items=ko.observableArray()
var itemsToRender=functionthattreturnslargerary()
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毫秒调用60次setTimeout
。这将需要更长的时间来处理整个收集。您还可以使用requestAnimationFrame
而不是setTimeout
,并查看其效果
编辑:已添加到(目前处于测试阶段,但似乎相当稳定)
注2:如果视图上的某些其他数据依赖于
viewModel.items
,则仍可以将其映射到原始数组itemsToRender
。例如,假设您希望显示集合中的项目数。如果使用viewModel.items()。为了避免这种情况,您可以首先基于itemsToRender
,而不是viewModel.items
,将大小绑定定义为dependenttobservable
。渲染完所有项目后,如果您认为合适,可以将其重新映射到viewModel.items
。这将说明问题:它减少了数据量,因为不需要强调这一点。下面是如何使用不同的方法立即渲染相同的html(2000行)。我不是说要这样做,但它只是表明淘汰不是非常优化…@Esailija-你的第一个例子实际上非常快。对于我们来说,只有当行数大于1000行时,这才是一个问题。我们一次提取所有数据的原因也有很多。所以,分页或以块的形式发送数据并不是一个真正的选项。你认为这应该作为一个bug提交吗?从技术上讲,这不是一个bug,但也许他们应该知道它。同时,您可以使用模板吐出一个字符串,并以与第二个示例相同的方式设置html(不是字面意义上的,而是使用.html
而不是[0].innerHTML
)。