简体   繁体   English

嵌套的辅助函数和性能

[英]Nested helper functions and performance

Nested helper functions can be useful for making your code more understandable. 嵌套的辅助函数可以使您的代码更易于理解。 Google even recommends using nested functions in their style guide . Google甚至建议在其样式指南中使用嵌套函数。 I'm wondering about the instantiation of these nested functions and performance. 我想知道这些嵌套函数和性能的实例化。 For example, 例如,

work(1);
work(2);

function work(a) {
    // do some stuff
    log();
    // do some more stuff
    function log() {
        console.log(a);
    }
}

work is instantiated once, but is log instantiated twice? work实例化一次,但是log实例化两次?

If log is instantiated every time work is executed, would it generally be recommended not to nest functions? 如果每次执行work都会实例化log ,那么通常建议不要嵌套函数吗? Instead, write code like the following 相反,编写如下代码

work(1);
work(2);

function work(a) {
    // do some stuff
    log(a);
    // do some more stuff
}

function log(a) {
    console.log(a);
}

These examples are overly trivial and the question is more about the general case. 这些例子过于简单,问题更多的是一般情况。

work is instantiated once, but is log instantiated twice? 工作实例化一次,但是日志实例化两次?

Yes, on each call to work . 是的,每次打电话都要工作

would it generally be recommended not to nest functions? 通常建议不要嵌套功能吗?

Why not? 为什么不? I presume you're hinting at performance issues. 我认为你暗示了性能问题。

Whether a practice is good or bad depends on your reasons for using it. 练习是好还是坏取决于你使用它的原因。 In the case of simple helpers, it's good to keep them local because it means you can make them suitable just for your special case and not worry about the extra cruft of a general function. 在简单的帮助器的情况下,最好将它们保持在本地,因为这意味着您可以使它们适合您的特殊情况,而不用担心一般功能的额外缺点。 Eg to pad a number with a leading zero: 例如,填充前导零的数字:

function pad(n) {
  return (n<10? '0' : '') + n; 
}

works very well as a helper where n is expected to always be in the range 0 to 99, but as a general function is missing a lot of features (dealing with non–number n, -ve numbers, etc.). 作为一个辅助工作非常好,其中n预计总是在0到99的范围内,但是作为一般函数缺少很多功能(处理非数字n,-ve数等)。

If you are concerned about performance, you can always use a closure so the helper is only instantiated once: 如果您担心性能,可以始终使用闭包,这样助手只会实例化一次:

var work = (function() {

  function log() {
    console.log(a);
  }

  return function (a) {
    // do some stuff
    log();
    // do some more stuff
  };
}());

Which can also make sense where log is used by more than one function within the closure. 在闭包内多个函数使用日志的情况下,这也是有意义的。

Note that for a single case, this is very much a micro optimisation and not likely to deliver any noticeable difference in performance. 请注意,对于单个案例,这非常微观优化,并且不太可能在性能上产生任何明显的差异。

Nested function-objects are instantiated and added to the LexicalEnvironment created when an enclosing function is run. 实例化嵌套的函数对象,并将其添加到运行封闭函数时创建的LexicalEnvironment Each of these nested functions will also have a [[Scope]] property created on them. 这些嵌套函数中的每一个都将在它们上创建[[Scope]]属性。 In addition when a nested function is run, a new LexicalEnvironment object will be created and the [[Scope]] copied to its outer property. 此外,当运行嵌套函数时,将创建一个新的LexicalEnvironment对象,并将[[Scope]]复制到其outer属性。

When the enclosing function completes, then the nested function-object and its associated memory will be eligible for garbage collection. 当封闭函数完成时,嵌套的函数对象及其相关的内存将有资格进行垃圾回收。

This process will repeat for every call to the outer function. 对于外部函数的每次调用,此过程都将重复此过程。

Contrast this with your second implementation, where the function-object need only be created once; 将此与第二个实现进行对比,其中函数对象只需创建一次; likewise its garbage collection. 同样它的垃圾收集。

If this is a "hot" function (ie called many times) then the second implementation is infinitely preferable. 如果这是“热”函数(即多次调用),那么第二种实现是无限优选的。

RobG is right. RobG是对的。 Performance us affected by instantiating functions for each work thread. 性能我们受每个工作线程的实例化函数的影响。 Whether it is a noticeable problem or not really comes down to how many simultaneous active working threads you have, as this affects memory consumption as well as execution speed. 它是否是一个明显的问题实际上归结为你有多少同时活动的工作线程,因为这会影响内存消耗和执行速度。

If performance is a big issue on your application (eg a complex, heavy function) and you only want to use the function in one place, closures are the way to go. 如果性能是您的应用程序的一个大问题(例如,复杂,繁重的功能),并且您只想在一个地方使用该功能,那么闭包是可行的方法。

If the function you're calling from "work" is to be used from several parts of your code, it's better to keep them separate instead of nesting them. 如果您从“工作”调用的函数是从代码的几个部分使用的,那么最好将它们分开而不是嵌套它们。 This makes to keep the code updated simpler (as you only update it in one place). 这使得代码更新更简单(因为您只在一个地方更新它)。

Most JS engines parse code only once (even for nested functions) so the work involved in instantiating functions is not a big issue. 大多数JS引擎只解析一次代码(即使对于嵌套函数),因此实例化函数所涉及的工作不是一个大问题。

Memory usage, on the other side, can be an issue if you have many nesting levels as well as several simultaneous threads or event listeners, so nesting should be managed carefully in these cases (on large-scale applications). 另一方面,如果您有许多嵌套级别以及多个同时线程或事件侦听器,则内存使用可能会成为问题,因此在这些情况下(在大型应用程序中)应仔细管理嵌套。

Yes. 是。 Instantiation occurs each time you invoke the nested functions. 每次调用嵌套函数时都会发生实例化。 Instantiating functions does use CPU time but it's not as important as parsing. 实例化函数确实使用CPU时间,但它不像解析那么重要。

So, for the general case (not the case now that you mention that your functions will be invoked many times per second), parsing time is more relevant than instantiation. 因此,对于一般情况(不是现在你提到你的函数每秒会被调用多次),解析时间比实例化更有意义。

In this case, nesting functions will use a lot of memory and CPU time,CSO it's best to use RobG's solution (closures), where functions are instantiated once and they are simply called, causing less memory usage. 在这种情况下,嵌套函数将使用大量的内存和CPU时间,CSO最好使用RobG的解决方案(闭包),其中函数被实例化一次并且它们被简单地调用,从而导致更少的内存使用。

If you want more optimized code in this critical piece of code, you should try to use as few functions as possible as this will work faster, albeit at the expense of losing code readability and maintainability. 如果您希望在这段关键代码中使用更多优化代码,则应尽量使用尽可能少的函数,因为这样可以更快地工作,尽管代价是丢失代码可读性和可维护性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM