我正在开发一个应用程序,它将进行统计计算,然后用D3.js显示结果数据。
在大多数情况下,我可以通过将实际计算传递给WebWorker来避免阻止UI。
完成计算后,数据点将排序并显示为d3.js.使用WebWorker中的DOM元素是令人讨厌的(though possible),即使工作者本身无法与DOM交互。我还是真的想避免这种情况。
我们说我有大约100万个数据点,它们将用d3进行排序和显示。 当js执行此任务时,如何避免UI冻结?
一个想法,在某种程度上有效:
d3代码看起来像这样:
d3.select ...
.sort ...
.enter ...
.attr ...
.attr ...
.style ...
这将全部执行一次。为了让render queue有机会在事物之间进行渲染,你可以做这样的事情:
let prom = new Promise((re, rj) => {
setTimeout(function() {
let val = d3.select ...
.sort ...
.enter ...
re(val);
}, 0);
});
prom.then(val => {
val = val.attr ...
.attr ...
.style ...
});
数据的d3操作的第一部分将被推送到回调队列,渲染队列有机会渲染,然后d3代码的下一部分将被执行(具有多个promise的更复杂的模型)可能)。仍然无法解决问题。它可能比一次执行所有内容要好一些,但如果单个部件本身耗时太长,UI仍将冻结。
有没有人知道这个问题的好方法?
答案 0 :(得分:1)
问题是您正在使用SVG,它必须添加Dom元素来表示您的所有条形图。即使您使用Web工作人员进行繁重的处理,添加数千个Dom元素,计算图像和绘制也是锁定主线程的原因。
你可以通过使用canvas来帮助解决这个问题,而不会出现大量的Dom元素并且更多地使用GPU。 D3 V4支持canvas,但需要一些重新架构才能使它工作。您也可以逐步渲染。棘手的一点是添加你的互动,因为你也没有单独的元素来附加听众。
答案 1 :(得分:0)
正如艾略特已经指出的那样,问题是D3会为DOM添加这么多元素。为了避免阻塞主线程,可以以块为单位绘制数据,如建议的here
我仍然需要先排序。