【问题标题】:Do Javascript engines do this kind of optimisation?Javascript 引擎会做这种优化吗?
【发布时间】:2020-05-18 09:05:09
【问题描述】:

NB 我已经阅读了一些关于 JS 引擎优化的文章,但其中大部分内容对我来说太技术性了,无法理解到足以适用于这个问题。我也知道并非所有的引擎都是一样的。我想我对 V8 和 Rhino 的处理特别感兴趣。

如果我创建一个表,然后是行,然后是单元格...然后我想在所有这些单元格上放置相同的键事件侦听器。

不仅为每个单元格创建这些侦听器需要一定的时间,这对于一个大表可能很重要,而且我假设每个侦听器函数都是独立存储的,即使每个监听函数其实是一样的。

我可以使用的另一种关键事件侦听器方法是在TABLE 上放置一个关键事件侦听器,并在运行期间计算每个keydown 事件,哪个单元格触发了此事件。我可以这样做

let elementOfInterest = document.activeElement;

“获取文档中当前聚焦的元素”来自here

根据我的实验,如果您在表格单元格内输入,TD 确实具有焦点,并且确实由上述调用返回。

这样,我只需要创建一个侦听器,我认为它会更快并且占用更少的内存。唯一(非常)轻微的缺点是必须花费时间通过上述调用来获取这个“活动元素”。而且,很可能,某些东西会以意想不到的方式抓住焦点 - 显然,如果你想监听单元格中文本的变化,最不容易出错的技术必须是使用附加到该单元格的监听器。

但我只是想知道:也许 Javascript 比这更聪明:也许如果您创建 100 个单独的单元侦听器,则某处将它们标识为“都一样”,并且只在内存中创建一个函数。例如,这是您通常期望从 Java 编译器获得的优化。

有没有发生过这样的优化?在这样的情况下,Javascript 有多聪明?还是只是“脚本,仅此而已”:所见即所得?

【问题讨论】:

  • 您所描述的称为event delegation,通常比拥有多个事件处理程序更受欢迎。我怀疑任何 JavaScript 运行时都足够聪明,总能将重复的事件处理程序减少为一个。

标签: javascript optimization memory-management javascript-engine


【解决方案1】:

语言本身的语义不允许将两个函数表达式“合并”为一个,即使它们在功能上是等效的:

> a = function(){return 'foo'};
ƒ (){return 'foo'}
> b = function(){return 'foo'};
ƒ (){return 'foo'}
> a === b
false

此外,当您开始考虑函数的闭包(例如,它使用的外部名称)时,事情会变得更加棘手。

所以不,这不是开箱即用的。

但是,对于您的用例,有两个优化:

  • 正如您所发现的,您可以使用 事件冒泡 并在祖先元素上添加事件侦听器,然后使用 event.target(最好而不是 document.activeElement)来确定它的位置最初的目标(event.currentTarget 将是处理程序所在的节点)
  • 如果你不能使用一个共同的祖先(提示:你几乎总是可以;document 是一个有效的目标),你可以定义一次函数(假设它不需要关闭任何动态变化的变量)并再次使用event.target,例如event.target.dataset 找出您正在处理的数据。

下面是一个演示两者的 sn-p。

function createButton(parent, datum) {
  const btn = document.createElement("button");
  btn.dataset.datum = datum;
  btn.innerHTML = datum;
  parent.appendChild(btn);
  return btn;
}

function eventHandler(event) {
  if(event.target.tagName !== "BUTTON") return;
  const msg = `real target: ${event.target} (datum="${event.target.dataset.datum}")\ncurrent target: ${event.currentTarget}`;
  alert(msg);
}

const p2 = document.getElementById("parent2");

// bubbling listener
const p1 = document.getElementById("parent1");
p1.addEventListener("click", eventHandler, false);
for(var i = 0; i < 10; i++) {
  createButton(p1, "p1-" + i);
}


// same function on multiple elements
for(var i = 0; i < 10; i++) {
  createButton(p2, "p2-" + i).addEventListener("click", eventHandler, false);
}
<div id="parent1"></div>
<div id="parent2"></div>

【讨论】:

  • 谢谢。啊,是的,event.target:这显然比假设你的活动元素是你的主题TD 更不容易出错。我不确定我是否理解您的第二个优化:您是否有机会输入一个 sn-p 代码,只是显示您将如何拦截此事件并获取 event.target
猜你喜欢
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多