JS中的站点加载结构

时间:2012-08-22 12:36:31

标签: javascript ajax load

我有一个网页,显示包含大量数据的图表。该图表是第三方闪存组件。

许多数据在初始页面加载后延迟加载并以AJAX形式输入到图表中。我的问题是,当发生这种情况时,页面会冻结几次,直到加载所有数据。这是一个问题,特别是因为页面加载,似乎一切准备就绪,但是当数据加载AJAX时,页面冻结。 一个很好的例子是我有的setInterval,它每1秒递增一个时钟。在AJAX加载过程中,此时钟在视觉上冻结。

如何避免这种情况?你会推荐一个不同的装载结构吗?

2 个答案:

答案 0 :(得分:2)

你的问题实际上非常简单,虽然解决方案有点棘手。您遇到“冻结”的原因是JavaScript是单线程的。页面的绘制发生在与处理数据相同的线程上。因此,如果您有一大块数据需要很长时间才能处理,您将会遇到用户界面冻结。

考虑以下示例:

http://jsfiddle.net/VT4Rs/

注意:如果屏幕在您点击时冻结,您可能需要稍微垃圾邮件“停止”按钮。此外,您可能需要调整“WEIGHT”变量以防止超长时间冻结,如果您的计算机/浏览器不如我的那么糟糕,或者如果您的计算机/浏览器比我的更好,则会导致冻结。

无论如何,重点是你会注意到“时钟”会在循环遍历所有这些数字时定期冻结。这是因为时钟更新发生在与数据“处理”相同的线程上。 setInterval()的工作方式,每隔X毫秒就会向事件队列添加一个事件(运行它传递的函数)。但是,为了防止在函数运行时间超过X毫秒的情况下出现一些严重问题,如果事件的上一次迭代已经在队列中,它将跳过向事件队列添加新事件。

因此,如果你有一些随机处理正在占用你的线程,那么你的setInterval显然会工作不正常。此外,由于浏览器界面在同一个线程上更新,您还可能导致“冻结”。

我发现解决此问题的最佳方法是将数据处理分解为更易于管理的“块”,然后使用setTimeout(fn, 0)定期将这些块推送到事件队列中,同时允许一些浏览器绘图和其他JavaScript根据需要进行处理。所以看看这个更新的例子,看看差异。我们仍在“处理”相同的数据,但我们将其分解为更小的块:

http://jsfiddle.net/Sjk29/

诀窍决定了制作大块的大小。你会发现调整块太大会导致失速和错过间隔。但是如果你把它做得太小,由于每个块的内置开销,处理数据需要花费很长时间。

好消息是你不限于指定的尺寸。在我的示例中,块大小由变量确定,您可能会注意到变量被引用到每个块。这意味着您可以根据用户浏览器上的实际性能调整该变量以调整块大小。你可能会这样做:

var CHUNK_SCALE = 8;
var CHUNK_SIZE = function() { return Math.pow(10, CHUNK_SCALE); };

(function() {
    var lastTick = new Date();

    setInterval(function() {
        var now = new Date();
        if (now - lastTick > 1500) {
            CHUNK_SCALE--;
        }
        lastTick = now;
    }, 1000);
}());

(参见:http://jsfiddle.net/ewP96/

这样,如果块大小开始太大(以可能影响UI性能的方式),那么它会自动将其缩放回用户计算机可以处理的内容。

JavaScript非常棒,嗯?

答案 1 :(得分:0)

我建议您使用html5而不是flash进行绘图,这可能会解决您的冻结问题。 你可以抬头看看:

  1. http://g.raphaeljs.com/
  2. http://www.rgraph.net/
  3. http://www.zingchart.com/
  4. http://d3js.org/
  5. http://processingjs.org/