【问题标题】:Jquery speed, using .html(string) is really really slow, how can I speed this up?Jquery 速度,使用 .html(string) 真的很慢,我怎样才能加快速度?
【发布时间】:2011-06-01 05:11:52
【问题描述】:

我有一个平均需要 250 毫秒才能完成的函数。我想在更短的时间内做到这一点,如果可以的话,

function updateDisplay() {
    var start = new Date().getTime();
    var $this = $(this);
    var data = $this.data('ansi');
    var html = '';
    for (var i = 0; i < data.screen.length; i++) {
        for (var j = 0; j < data.screen[i].length; j++) {
            html += data.screen[i][j];
        }
        html += '<br />';
    }
    var create = new Date().getTime();
    console.log('Build html: ' + (create-start));
    $this.html(html);
    var end = new Date().getTime();
    console.log('Update html: ' +(end-create));
}

我在setInterval 一侧调用此函数来更新我的显示,构建 html 字符串的时间为每帧 0 毫秒到 1 毫秒,但更新 html 的时间为 100 毫秒到 300 毫秒。有没有办法让它更快?

呸,打开 chrome 检查器来观看控制台会增加巨大的延迟 这是我目前的功能(如果来自 CD Sanchez,基本上是一个下降)。在没有检查器打开的情况下,更新 html 的运行时间约为 50 毫秒。这要好得多,但如果可以的话,我希望将其缩短到

function updateDisplay() {
    var start = new Date().getTime();
    var $this = $(this);
    var data = $this.data('ansi');
    var html = Array();
    for (var i = 0, length1 = data.screen.length; i < length1; ++i) {
        var a = data.screen[i]; // cache object
        for (var j = 0, length2 = a.length; j < length2; ++j) {
            html.push(a[j]); // push to array
        }
        html.push('<br />');
    }
    var create = new Date().getTime();
    this.innerHTML = html.join(''); // use innerHTML
    var end = new Date().getTime();
    $('#debug').html('Build html: ' + (create-start) + '<br/>Update html: ' + (end-create));
}

html 的示例值 - 第一行,直到 &lt;br&gt;

<span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">┌</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">─</span><span style="background-color:#000000;color:#ffffff;">┐</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><span style="background-color:#000000;color:#ffffff;">&nbsp;</span><br>

示例 - here,目前仅在 chrome 中进行了测试。在 IE 中工作的已知结...

更新 我已将我的代码转换为使用画布并直接绘制到该画布上。我不确定我是否以最好的方式做这件事,因为这是我第一次使用画布。就目前而言,我在 20 毫秒左右。这是我最满意的上限,不过 10 毫秒会好得多。

我不确定是否可以在样式中定义前景色和背景色并删除fillRect 调用,如果可以的话,这会加快速度。另一个问题是字体看起来不像纯 html 那样清晰,不确定我是否可以解决这个问题。上面链接的示例已更新。

function updateDisplay() {
    var start = new Date().getTime();
    var $this = $(this);
    var data = $this.data('ansi');
    for (var i = 0, length1 = data.screen.length; i < length1; ++i) {
        var a = data.screen[i]; // cache object
        for (var j = 0, length2 = a.length; j < length2; ++j) {
            data.ctx.fillStyle = a[j][0];
            data.ctx.fillRect (8*j, 14 * i, 8, 14);
            data.ctx.fillStyle = a[j][1];
            data.ctx.fillText(a[j][2], 8*j, 14 * i);
        }
    }
    var end = new Date().getTime();
    $('#debug').html('Frame Time: ' + (end-start));
}

上次更新 ctx.fillText 对于我的目的来说非常慢且不够准确。我将自己的字体定义为 8x16 数组,并使用ctx.fillRect 绘制每个像素。这要快得多,并且可以处理它接缝的字体子系统。

【问题讨论】:

  • 你试过this.innerHTML = html - 可能会快一点。
  • @CD Sanchez - 增加不多,我现在看到的是 100-250 毫秒。如果它有所不同,则 html 是一堆 spans,每个都有一个字符。
  • 您是否尝试过使用 Firebug 分析器?它可能会指出一些需要很长时间才能执行的区域。
  • @Justin808:嗯,我认为您测量的大部分时间都花在了 HTML 引擎渲染标记上(这可能非常复杂,具体取决于您的数据集有多大)。我真的想不出你可以用 JavaScript 做些什么来大大缩短时间。
  • 如果没有看到传递给html() 的实际字符串,很难在这里说任何有用的东西。给定一个测试用例,应该不难看出时间花在了哪里,但是……至少在某些浏览器上是这样。

标签: javascript jquery optimization


【解决方案1】:

这里有一些非常小的优化,我怀疑它们会有很大帮助,但无论如何你都可以这样做:

function updateDisplay() {
    var start = new Date().getTime();
    var $this = $(this);
    var data = $this.data('ansi');
    var html = [];
    for (var i = 0, length1 = data.screen.length; i < length; ++i) {
        var a = data.screen[i]; // cache object
        for (var j = 0, length2 = a.length; j < length2; ++j) {
            html.push(a[j]); // push to array
        }
        html.push('<br />');
    }
    var create = new Date().getTime();
    console.log('Build html: ' + (create-start));
    this.innerHTML = html.join(''); // use innerHTML
    var end = new Date().getTime();
    console.log('Update html: ' +(end-create));
}

当然,这些只是简单的 JavaScript 优化(在较新的浏览器上并没有那么有用)。听起来您需要简化 HTML 和可能的 CSS,以便 HTML 引擎可以更快地呈现它。

【讨论】:

  • 这是保持稳定刷新率的最快方法。其他仅更新某些字符的建议在大多数情况下会快得多,但相比之下会导致诸如清除显示之类的事情要慢得多。结果,我将其标记为正确。我将研究输出到画布元素而不是 html,看看它是否更快。
  • @Justin808:我打算这么建议,但我不确定切换到画布会有多大的麻烦。如果您有突破,请务必告诉我们:)。
  • canvas 正在运行,我的代码并没有发生巨大的变化。当我将其与上一个示例相提并论时,我将更新示例和问题
【解决方案2】:

为了理解这类问题,我发现 Dynatrace Ajax 版是最好的工具,因为它还可以判断渲染花费了多少时间,而不仅仅是 javascript 执行。可能还有其他类似的工具,我觉得这个很好。

我认为您可能需要重新考虑您的整个方法。编写 HTML 元素来创建动画绝不是一个好主意。这就是我们有canvas、svg和flash/silverlight之类的东西的原因。可能可以在一定程度上进行优化,但请改用正确的工具。也许不是您正在寻找的答案,但我认为,如果您使用 canvas 或 svg,无论是在性能方面,还是在可维护性方面,您都会对最终结果更加满意。

http://raphaeljs.com/reference.html#text 是一个不错的库

更新 1: 如果你真的想这样做,我会尝试稍微改变一下方法。现在你每次都重绘整个“网格”。查看动画看起来您应该每次只能更新一行。我认为您可以将每一行包装在一个 div 中,并且对于每一帧,您只需重写该行上 div 的内容。我会将对 div 的引用存储在一个数组中,这样您就可以避免在每一帧上运行选择器。

【讨论】:

  • 我讨厌将图形工具用于纯文本。如果必须的话,我会使用画布作为最后的手段,但我不想为此使用任何插件。
  • 更新了另一种可能对您有帮助的方法
  • 感谢您的更新。这个问题将是这种方法的可变刷新率。我将研究输出到画布,看看是否可以加快速度。
  • 我很确定您可以通过这种方法获得恒定的 FPS。除非画布成功,否则我今晚回家后可能会做一个演示。
  • canvas 正在运行,我的代码并没有发生巨大的变化。当我将其与上一个示例相提并论时,我将更新示例和问题
【解决方案3】:

您确定问题出在实际附加数据而不是渲染数据上吗?如果您的标记很复杂(可能有很多 spans,具体取决于有多少),那么新标记的渲染时间是不可忽略的。如果您将调用.html(html) 更改为.text(html),时间会发生什么变化?

我不建议您将其作为最终修复(text 不解析 HTML 标记),但它可以帮助您查看渲染或追加时间。

【讨论】:

  • 是的,将其更改为 .text 也会使其大约 1 毫秒......这似乎是渲染时间。问题是我需要每个字符的样式信息。
【解决方案4】:

尚未测试,但假设data.screen[i] 是一个字符串数组,使用join 函数可能会加快速度:

(循环)

for (var i = 0; i < data.screen.length; i++) {
        html += data.screen[i].join("");
    html += '<br />';
}

连接字符串可能看起来像一个简单的加法,但每次使用+= 时都会创建一个新的字符串对象。我建议使用 StringBuffer 之类的东西。

编辑:

好的,在您的示例代码中,您尝试每隔几毫秒替换数千行 html,每次只更改一个字符。如果每次只更改一个字符,则可以将延迟减少约 99%

【讨论】:

  • 是的,但整个屏幕可以向上滚动,所有字符都需要替换。我需要稳定的刷新率,而不是可变的。
猜你喜欢
  • 2011-02-16
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多