【问题标题】:JavaScript - is it a smart idea to declare a function to a variable? [closed]JavaScript - 将函数声明为变量是一个聪明的主意吗? [关闭]
【发布时间】:2016-08-21 07:45:38
【问题描述】:

正如标题所述。 如果您关心性能,将函数声明为变量是一个聪明的主意吗?例如在这种情况下:我正在创建一个将被重复调用 x 次的函数。此函数包含一对变量并且不接受参数。此变量之一包含一个匿名函数,并且此变量/函数将被调用每次父已被调用。

所以基本上结构应该是这样的:

   function myFunction() {
  var foundElements = document.querySelectorAll("*"),
    updateElements = function() {
      console.log("Hello world, i've been called to work as a slave!");
    };

  if (foundElements.length > 0) {
    updateElements();
  }
}

我是否最好将此函数声明为命名/分隔函数?或者这是要走的路? (因为我认为这种方法会导致系统在每次调用父级时重新创建函数,如果我错了,请纠正我)

提前致谢。

【问题讨论】:

  • 我同意,您应该阅读更多关于此的内容:benalman.com/news/2010/11/…
  • 除非 x 是几十万的量级,否则没有,没有可测量的差异(即使那样也不会有实际差异)。它不会成为这里的瓶颈。例如,一个querySelectorAll() 调用实际上可能比任何差异都慢数百万倍。
  • @Juhana 但是如果该函数是子子 (needed) 函数,如果当前元素与我的 IF 不匹配,可以再次调用该函数 要求。然后只为这个函数创建一个命名函数(使其正常工作)会有点愚蠢,对吧?
  • 我不太明白你在说什么,但让它正常工作听起来一点也不傻。关键是这不是性能问题。

标签: javascript function variables call anonymous


【解决方案1】:

因为我认为这种方法会导致系统重新创建函数 每次调用父母时,如果我错了,请纠正我

我不确定 javascript 编译器是如何工作的,但我怀疑它们是否会在每次调用“父级”时编译该函数。至少如果我要编写一个编译器,它会将编译后的函数存储在缓存中,并且每次都使用该缓存。

无论如何编译一个 javascript 函数不会导致性能问题,因为它非常便宜。访问 DOM 的成本要高得多,所以如果我是你,我会担心 document.querySelectorAll("*") 部分,尤其是 * 部分...

【讨论】:

  • 这个。还有更重要的事情需要优化。
  • 某些 javascript 实现可能会在每个函数调用上编译。这取决于闭包是如何实现的。但是对于程序员来说,它必须像每次调用都编译函数一样工作,否则闭包将无法按预期工作。见:stackoverflow.com/questions/38364782/…
  • querySelectorAll/getElementsByTagName 是唯一可用于检索当前 DOM (在 Vanilla JS 中) 中的每个元素的“变体”。使用 jQuerys ($(" * ", document)) 会慢很多吗?
  • @Bilal075_ " that can be used to retrieve every single element in the current DOM" 你为什么要这样做?这没有意义,至少对我来说。顺便提一句。如果你想了解更多关于 jQuery 和 vanilla 性能的信息,这里有很多有趣的文章,SO。本主题中的问题。 stackoverflow.com/questions/4651923/…toddmotto.com/…sitepoint.com/jsperf1
【解决方案2】:

是的,创建一个新的函数实例确实有一些可衡量的开销。这种开销是否会对实际代码产生任何影响完全是另一回事。

例如,考虑这个简单的基准测试,它以各种或多或少低效的方式切换布尔标志:

var suite = new Benchmark.Suite;
var flag = true;

suite.add('baseline', function() {
  flag = !flag;
});

suite.add('local helper function', function() {
  var f = function(x) { return !x };
  flag = f(flag);
});

var g = function(x) { return !x };
suite.add('external helper function', function() {
  flag = g(flag);
});

console.log('Running benchmark on ' + Benchmark.platform.description );
suite.on('cycle', function(event) { console.log(' - ' + event.target) });
suite.on('complete', function() { console.log('Fastest is ' + this.filter('fastest').map('name')) });
suite.run({ 'async': true });
<script src="https://cdn.jsdelivr.net/g/lodash@4.15.0,platform.js@1.3.1,benchmarkjs@2.1.1"></script>

当我在 Chrome 52 上运行此基准测试时,我得到以下结果:

Running benchmark on Chrome 52.0.2743.116 32-bit on Windows Server 2008 R2 / 7 64-bit
 - baseline x 75,600,376 ops/sec ±0.90% (62 runs sampled)
 - local helper function x 5,912,099 ops/sec ±0.36% (63 runs sampled)
 - external helper function x 74,912,931 ops/sec ±1.05% (62 runs sampled)
Fastest is baseline,external helper function

有点令人惊讶的是,基线代码和调用外部函数来切换变量的版本几乎同样快;差异在统计上并不显着(即它与随机噪声实际上无法区分),benchmark library 报告两者并列第一。 Chrome 的 JS 引擎似乎能够内联外部辅助函数,使两个版本实际上相同。然而,在每次迭代中创建和调用新辅助函数实例的版本几乎要花费 13 倍的时间,这反映了创建和调用函数的开销。

也就是说,13 倍的开销与切换真/假标志的琐碎操作进行了比较。从某种角度来看,让我们看看如果我在基准代码中添加一个简单的 DOM 查询会发生什么,以模拟一个更真实的用例:

var suite = new Benchmark.Suite;
var flag = true;

suite.add('baseline', function() {
  var foundElements = document.querySelectorAll("*");
  flag = !foundElements;
});

suite.add('local helper function', function() {
  var f = function(x) { return !x };
  var foundElements = document.querySelectorAll("*");
  flag = f(foundElements);
});

var g = function(x) { return !x };
suite.add('external helper function', function() {
  var foundElements = document.querySelectorAll("*");
  flag = g(foundElements);
});

console.log('Running benchmark on ' + Benchmark.platform.description );
suite.on('cycle', function(event) { console.log(' - ' + event.target) });
suite.on('complete', function() { console.log('Fastest is ' + this.filter('fastest').map('name')) });
suite.run({ 'async': true });
<script src="https://cdn.jsdelivr.net/g/lodash@4.15.0,platform.js@1.3.1,benchmarkjs@2.1.1"></script>

这一次,结果是这样的:

Running benchmark on Chrome 52.0.2743.116 32-bit on Windows Server 2008 R2 / 7 64-bit
 - baseline x 898,041 ops/sec ±25.49% (39 runs sampled)
 - local helper function x 605,107 ops/sec ±30.57% (47 runs sampled)
 - external helper function x 720,695 ops/sec ±34.60% (38 runs sampled)
Fastest is baseline,external helper function

是的,排名还是一样(虽然时间上的差异要高得多),但是现在使用内部辅助功能的版本只比使用外部辅助功能的版本慢 20% 左右。 (这仍然超出了我的预期;显然,querySelectorAll() 非常快,至少在像 sn-p 这样的非常简单的文档上是如此。)如果您添加更多代码来实际做某事有了这些 DOM 元素,相对差异会变得更小。

所以是的,如果您可以选择在另一个调用它的函数内部或外部定义您的辅助函数(并且它本身被重复调用),没有其他理由更喜欢一个选项而不是另一个 ,那么将定义保留在外部以避免重复创建函数对象(并使 JS 引擎的内联更容易)会更有效一些。但在实践中,除非您发现这个嵌套函数正是代码中对性能至关重要的部分,否则您可能不应该担心它。

【讨论】:

    猜你喜欢
    • 2012-12-21
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 2021-08-10
    相关资源
    最近更新 更多