node.js:封闭样式代码是否比ES6类样式有害?

时间:2018-07-26 01:17:41

标签: javascript node.js closures

(请原谅我的英语)

下面是一个非常简化的示例代码。

function test(limit) {
    let count = 0, undone = true;

    function inc() {
        // do something
        count++;
        if(count == limit)
            undone = false;
    }

    while(undone) {
        // do something
        inc();
    }
}

我经常使用闭包样式函数,例如上例中的inc()。因为共享变量非常方便。
但是,有人告诉我,我的编码风格非常有害。因为每次调用test()(在上面的示例中),inc()都会在内存中重复分配。他建议我改用ES6类样式代码。

我不同意他的看法,但不确定。闭包样式代码真的比ES6类样式有害吗?

  

修改

     

我对这个问题做了一个简单的基准测试,如前所述   在下面。

     

https://stackoverflow.com/a/51530670/7339376

     

结果令我有些惊讶。我错了。我的   顾问是正确的。

3 个答案:

答案 0 :(得分:2)

对于上面的示例,使用闭包来维护私有变量和使用类来处理同一件事在理论上没有显着差异。

每次调用/usr/lib函数时,使用闭包都会分配一个新的函数对象。

每次调用test函数时,使用类都会分配一个新对象。

理论上,两者都分配内存,并且都花时间调用构造函数。

有些人可能会反对这样的事实,即每次只将类中的方法编译一次时,就需要重新编译该函数。请注意,闭包也可以优化为仅编译一次。因此,这只是一个微观优化问题。

从学术上讲,闭包和类是等效的。我认为,当Lisp在不对语言进行任何修改的情况下使用闭包将对象和类实现为库时,我们首先理解了这一点,但是从那以后,有研究论文发表,证明闭包和类在计算上是等效的-只有它们的功能集略有不同。 / p>

关于优化,您唯一要做的就是对代码进行基准测试。如果足够好,则请勿更改您的代码。与此相反的任何观点仅是宗教/政治观点,应予以忽略。如果您需要更好的性能,则对代码进行概要分析以找到真正的瓶颈。这可能是瓶颈,也可能不是。不要优化不会减慢速度的代码。

一天结束时,请写出最清晰,最易读的代码。

答案 1 :(得分:0)

这是一个非常普遍的论点,反对将功能直接作为属性添加到对象,或者通过在其他对象内部定义它们来添加。但是您不需要ES6来更改此设置。普通的老式函数原型已经为此使用了很长时间。

例如,在此代码中,inc函数仅创建一次,而不管创建了多少测试对象。<​​/ p>

function test(limit) {
  this.limit = limit
  this.count = 0
  this.undone = true;
}
test.prototype.inc = function() {
  console.log("something", this.count)
  this.count++;
  if (this.count == this.limit)
    this.undone = false;
}

let t = new test(10)
while (t.undone) {
  t.inc()
}

您还可以使用简单的旧对象原型来执行此操作,该原型使您可以与多个对象共享同一功能:

const test = {
    limit: undefined,
    count: 0,
    undone: true,
    inc() {
        console.log("something", this.count)
        this.count++;
        if(this.count == this.limit)
            this.undone = false;
    }
}

let t = Object.create(test)
t.limit = 5
while(t.undone) {
    t.inc()
} 

let p = Object.create(test)
p.limit = 5
while(p.undone) {
    p.inc()  // <-- same inc() as t.inc()
} 

答案 2 :(得分:0)

(请原谅我的英语)

我刚刚使用perf命令在Ubuntu 16.04计算机上进行了基准测试,结果让我感到非常惊讶。我错了。我的顾问是对的。
我简单的ES6类样式代码的效率是闭包样式等效代码的2到3倍。

下面是class.js,ES类样式,简单的循环代码。

class test {
    constructor(limit) {
        this.limit = limit;
        this.count = 0;
        this.undone = true;

        while(this.undone) {
            this.inc();
        }
    }

    inc() {
        this.count++;
        if(this.count == this.limit)
            this.undone = false;
    }
}

for(let i=0; i<5000000; i++) {
    new test(100)
}

perf stat node class的结果(执行3次)。

 Performance counter stats for 'node class':

       1055.290800      task-clock (msec)         #    1.002 CPUs utilized          
                28      context-switches          #    0.027 K/sec                  
                 6      cpu-migrations            #    0.006 K/sec                  
             2,554      page-faults               #    0.002 M/sec                  
     2,858,088,136      cycles                    #    2.708 GHz                    
       892,221,452      stalled-cycles-frontend   #   31.22% frontend cycles idle   
   <not supported>      stalled-cycles-backend   
     5,815,629,017      instructions              #    2.03  insns per cycle        
                                                  #    0.15  stalled cycles per insn
     2,561,547,866      branches                  # 2427.338 M/sec                  
         6,776,303      branch-misses             #    0.26% of all branches        

       1.053429789 seconds time elapsed


 Performance counter stats for 'node class':

       1057.919398      task-clock (msec)         #    1.002 CPUs utilized          
                28      context-switches          #    0.026 K/sec                  
                 6      cpu-migrations            #    0.006 K/sec                  
             2,555      page-faults               #    0.002 M/sec                  
     2,856,736,277      cycles                    #    2.700 GHz                    
       890,790,850      stalled-cycles-frontend   #   31.18% frontend cycles idle   
   <not supported>      stalled-cycles-backend   
     5,815,147,889      instructions              #    2.04  insns per cycle        
                                                  #    0.15  stalled cycles per insn
     2,561,451,165      branches                  # 2421.216 M/sec                  
         6,778,756      branch-misses             #    0.26% of all branches        

       1.056058390 seconds time elapsed


 Performance counter stats for 'node class':

       1054.245840      task-clock (msec)         #    1.002 CPUs utilized          
                27      context-switches          #    0.026 K/sec                  
                 9      cpu-migrations            #    0.009 K/sec                  
             2,553      page-faults               #    0.002 M/sec                  
     2,856,022,458      cycles                    #    2.709 GHz                    
       890,300,670      stalled-cycles-frontend   #   31.17% frontend cycles idle   
   <not supported>      stalled-cycles-backend   
     5,815,241,984      instructions              #    2.04  insns per cycle        
                                                  #    0.15  stalled cycles per insn
     2,561,469,424      branches                  # 2429.670 M/sec                  
         6,768,183      branch-misses             #    0.26% of all branches        

       1.052295061 seconds time elapsed


 
下面是closure.js(关闭样式等效于class.js)

function test(limit) {
    let count = 0, undone = true;

    function inc() {
        count++;
        if(count == limit)
            undone = false;
    }

    while(undone) {
        inc();
    }
}

for(let i=0; i<5000000; i++) {
    test(100)
}

还有perf stat node closure的结果(也执行了3次)。

 Performance counter stats for 'node closure':

       2377.214932      task-clock (msec)         #    1.002 CPUs utilized          
               389      context-switches          #    0.164 K/sec                  
                 9      cpu-migrations            #    0.004 K/sec                  
             3,141      page-faults               #    0.001 M/sec                  
     6,560,657,082      cycles                    #    2.760 GHz                    
     1,946,461,285      stalled-cycles-frontend   #   29.67% frontend cycles idle   
   <not supported>      stalled-cycles-backend   
    16,046,574,530      instructions              #    2.45  insns per cycle        
                                                  #    0.12  stalled cycles per insn
     6,110,865,652      branches                  # 2570.599 M/sec                  
         6,953,209      branch-misses             #    0.11% of all branches        

       2.371426270 seconds time elapsed


 Performance counter stats for 'node closure':

       2381.292759      task-clock (msec)         #    1.002 CPUs utilized          
               391      context-switches          #    0.164 K/sec                  
                 8      cpu-migrations            #    0.003 K/sec                  
             3,142      page-faults               #    0.001 M/sec                  
     6,558,376,504      cycles                    #    2.754 GHz                    
     1,943,542,624      stalled-cycles-frontend   #   29.63% frontend cycles idle   
   <not supported>      stalled-cycles-backend   
    16,046,969,491      instructions              #    2.45  insns per cycle        
                                                  #    0.12  stalled cycles per insn
     6,110,955,583      branches                  # 2566.234 M/sec                  
         6,967,852      branch-misses             #    0.11% of all branches        

       2.375578434 seconds time elapsed


 Performance counter stats for 'node closure':

       2376.579401      task-clock (msec)         #    1.003 CPUs utilized          
               388      context-switches          #    0.163 K/sec                  
                 7      cpu-migrations            #    0.003 K/sec                  
             3,125      page-faults               #    0.001 M/sec                  
     6,562,861,447      cycles                    #    2.761 GHz                    
     1,947,165,390      stalled-cycles-frontend   #   29.67% frontend cycles idle   
   <not supported>      stalled-cycles-backend   
    16,051,805,939      instructions              #    2.45  insns per cycle        
                                                  #    0.12  stalled cycles per insn
     6,111,984,155      branches                  # 2571.757 M/sec                  
         6,962,744      branch-misses             #    0.11% of all branches        

       2.369557403 seconds time elapsed