【问题标题】:Speeding up JavaScript function that changes colour of div-element constructed 'led display'加速改变 div 元素颜色的 JavaScript 函数构造的“led 显示”
【发布时间】:2018-07-20 11:29:16
【问题描述】:

背景资料

对于我正在进行的项目,我需要模拟一排可以显示不同二进制数字的 LED。使用border-radius: 50% 的大量 div 元素,我可以制作成行的“LED”。然后,JavaScript 函数可以应用不同的 css 类来更改每个元素的颜色,以模拟它是打开还是关闭。我拥有的另一个功能是工具提示,当您将鼠标悬停在 LED 上时,它会显示 LED 显示的数值。

问题

我遇到的问题是这种方法的性能。这是因为我的网页将使用几十个这样的行,并且每行都会通过requestAnimationFrame() 在每次屏幕刷新时更新其值。目前,在我的笔记本电脑上更新页面上 LED 行的每个实例大约需要 5 毫秒。这绝对低于我们在 60Hz 时每帧的 16.6 毫秒 - 但是对于我的项目,每帧还需要完成许多其他事情,这确实为这些事情留下了很少的时间。

一个例子

我当前的实现示例可在此处的 js fiddle 上找到:https://jsfiddle.net/dL6jq7or/25/。单击“基准”文本并检查控制台以查看将 LED 行更新 50,000 次所需的时间。您可以使用它来快速评估您提出的任何想法的性能。

注意:我每次都将显示设置为不同的值,以避免浏览器在检测到没有发生实际更改时可能会采取的任何巧妙技巧。这些 LED 行的实际应用几乎总是每次都给它们一个不同的值,因此这使得基准更加现实。

我已经尝试过加快速度

我在 led_strips 对象中缓存了对 LED 的引用,这提高了性能,因为浏览器不再需要每次都执行 document.getElementById()

我听说在元素中添加/删除 css 类比直接使用 JavaScript 更改其 css 属性要快。这就是代码添加或删除 on 类以更改 LED 状态的原因。

我发现首先检查 led div 是否具有 on 类,然后再尝试将其删除(反之亦然),这会提高性能。

注意事项

LED 灯条没有固定大小 - 其中的 LED 数量应仅由其中包含的 led 类 div 的数量决定。

并非所有 LED 灯条都有工具提示 - 如果它们应该有一个工具提示,那么容器 div 将具有 tooltip-enabled 类并包含一个 tooltip-content div。

您会看到我注释掉了 display_number_on_leds 函数的一部分,该部分仅在工具提示可见时才更新。此检查提供了很大的性能提升,但意味着如果您在更改后将鼠标悬停在条上,工具提示可能会显示错误的值。这是不可接受的。

浏览器更改显示数字所花费的大部分时间似乎是重新计算页面的布局/样式。避免这种情况肯定会提高性能,但我不知道该怎么做。

总结

任何人都可以找到一种方法来加速 display_number_on_leds 函数,以保留我目前拥有的功能吗?如果这种方法不可能更快地工作,是否有任何替代方法可以更快(可能是画布?)。

【问题讨论】:

  • 与您的问题相关的代码直接属于您的问题,而不仅仅是转储在外部站点上。请阅读How to Askminimal reproducible example,然后进行相应的编辑。 (作为交换,其余的解释可能会减少一点,这可能是 TL;对于某些人来说已经是 DR 领域了。)
  • 这是一些不错的 JS 代码。您使用按位运算符,缓存 DOM 元素,使用我什至不知道的函数,例如 String.repeatNumber.toString... 我认为您的代码没有显着提高速度的可能性。 IMO 它几乎是尽可能快的。 (仅供参考,您的基准测试在我的 Chrome 机器上需要 650 到 700 毫秒)
  • 感谢您对代码的反馈。我怀疑可能没有什么改进的余地,但我不是专家,所以我问了。
  • 至于我的问题的编辑,我是否应该在问题本身中包含一些关键的sn-ps代码?我把它全部放在 jsfiddle 上,因为我不想让问题太长。

标签: javascript html css performance optimization


【解决方案1】:

由于您没有在工具提示中设置任何 HTML,仅设置文本,因此您可以改用 nodeValuetextContentinnertext 之一。 nodeValue 似乎在这里给出了最好的结果,尽管我在 Chrome 66 上的速度提高了 50% 以上。

运行你的原始代码(使用innerHTML)10 次给我:

50,000 iterations: 483.121826171875ms
50,000 iterations: 430.60400390625ms
50,000 iterations: 431.64599609375ms
50,000 iterations: 454.813232421875ms
50,000 iterations: 428.945068359375ms
50,000 iterations: 451.15673828125ms
50,000 iterations: 436.782958984375ms
50,000 iterations: 432.094970703125ms
50,000 iterations: 551.495849609375ms
50,000 iterations: 442.85400390625ms

使用tooltip.childNodes[0].nodeValue = text;

50,000 iterations: 212.26611328125ms
50,000 iterations: 198.85595703125ms
50,000 iterations: 206.324951171875ms
50,000 iterations: 201.528076171875ms
50,000 iterations: 202.0048828125ms
50,000 iterations: 195.52685546875ms
50,000 iterations: 207.598876953125ms
50,000 iterations: 202.48291015625ms
50,000 iterations: 207.677001953125ms
50,000 iterations: 197.98583984375ms

使用tooltip.textContent = text;

50,000 iterations: 259.39892578125ms
50,000 iterations: 221.156005859375ms
50,000 iterations: 238.042236328125ms
50,000 iterations: 212.44189453125ms
50,000 iterations: 221.1201171875ms
50,000 iterations: 225.68212890625ms
50,000 iterations: 226.552001953125ms
50,000 iterations: 209.56494140625ms
50,000 iterations: 215.00439453125ms
50,000 iterations: 222.412109375ms

使用tooltip.innerText = text;

50,000 iterations: 208.27099609375ms
50,000 iterations: 196.996826171875ms
50,000 iterations: 204.372802734375ms
50,000 iterations: 208.3291015625ms
50,000 iterations: 266.80810546875ms
50,000 iterations: 203.071044921875ms
50,000 iterations: 208.48876953125ms
50,000 iterations: 206.7939453125ms
50,000 iterations: 203.4111328125ms
50,000 iterations: 214.489013671875ms

编辑

除了上述之外,您还可以做一些其他事情来稍微提高性能。

1.

num_dec_digitsnum_hex_digits 在迭代之间不会改变值,因为它们仅取决于 LED 的数量,因此可以在 get_led_references() 中计算:

function get_led_references(id) {
  var ref = document.getElementById(id);
  var has_tooltip = ref.children[0].className == "tooltip_content";
  var leds = Array.prototype.slice.call(ref.children);
  var references = {
    leds: leds,
    tooltip: has_tooltip ? leds.shift() : null
  };

  var log10_pow2 = Math.log10(Math.pow(2, leds.length));
  references.num_dec_digits = Math.ceil(log10_pow2);
  references.num_hex_digits = Math.ceil(log10_pow2 / Math.log10(16));

  return references;
}

当然,如果这样做,那么display_number_on_leds() 必须相应地更改。

2.

get_padded_num() 函数中,您当前正在分配比您需要的更长的新字符串。至少对于您提供的示例数据,在填充字符之前的 while 循环似乎执行速度快了 10-20%:

function get_padded_num(number, length, base) {
  var str = number.toString(base);
  while (length > str.length) {
    str = '0' + str;
  }

  return str;
}

因此,添加了修改后,现在的执行时间为:

50,000 iterations: 165.459716796875ms
50,000 iterations: 169.538818359375ms
50,000 iterations: 176.2109375ms
50,000 iterations: 170.885986328125ms
50,000 iterations: 167.305908203125ms
50,000 iterations: 169.608154296875ms
50,000 iterations: 168.797119140625ms
50,000 iterations: 175.070068359375ms
50,000 iterations: 165.182861328125ms
50,000 iterations: 169.580810546875ms

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-02
    • 2012-03-15
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    相关资源
    最近更新 更多