Javascript运行密集的可视化操作而不冻结浏览器

时间:2012-11-09 17:29:06

标签: javascript d3.js

从之前在类似方面提出的问题,我可以推断,由于Javascript是单线程的,可能会考虑像setTimeout这样的方法,但是我似乎没有得到任何渐进的结果。我的任务涉及DOM操作,所以我可以不依赖于HTML5 Web Workers

这里的问题是绘制统计操作的大数据集,例如Resampling.For我们使用d3库,在一般说明中,它接受整个数据集并计算图表的各种参数,如箱数,围绕冗长循环的一种方法是将数据集分解为更小的块,但仍然必须立即传递整个数据集以计算作为瓶颈的参数。

我所指的一个很好的例子是用于生成github存储库的图形(例如,https://github.com/mbostock/d3/graphs/contributors)。我们可以看到绘图操作尽管是密集的但不会干扰浏览器任务。关于如何处理类似线路的任何线索?

1 个答案:

答案 0 :(得分:2)

(我不确定您链接的图表是否适合作为密集型任务,但无论如何)

通过使用超时分解任务,我获得了很好的结果。说你正在做这样的事情:

var largeSelection = d3.selectAll('svg circle')
  .data(aReallyLargeDataset);// Expensive Bind Operation

largeSelection.enter()
  .append('circle')// Lots of appending
  .attr('r', function() { /* expensive calculations */ return ... });

largeSelection// Many refreshes
  .attr('cx', function() { /* more expensive calculations */ return ... });

这可能需要浏览器1秒渲染(很长一段时间,考虑到在此任务期间所有内容都将被冻结)。你可以通过这样分解来改善它:

setTimeout(function() {
  var largeSelection = d3.selectAll('svg circle')
    .data(aReallyLargeDataset);// Expensive Bind Operation

  setTimeout(function() {
    largeSelection.enter()
      .append('circle')// Lots of appending
      .attr('r', function() { /* expensive calculations */ return ... });

    setTimeout(function() {
      largeSelection// Many refreshes
        .attr('cx', function() { /* more expensive calculations */ return ... });
    }, 100);

  }, 100);

}, 100);

对于令人讨厌的筑巢和超时感到抱歉。您可以以更具可读性/可扩展性的方式重构/抽象它。在任何情况下,以这种方式分解任务使浏览器有机会“呼吸”并更新DOM,从而从用户的角度来看,应用程序看起来并不“卡住”。

如果仍然感觉迟钝,你可以进一步分解:

var entering = largeSelection.enter()
  .append('circle');// Lots of appending

  setTimeout(function() {
    entering.attr('r', function() { /* expensive calculations */ return ... });
  }, 100);