Alexander Myshov
Alexander Myshov

Reputation: 3101

Are arrow functions faster (more performant, lighter) than ordinary standalone function declaration in v8?

I am asking this question because I and my colleague have a dispute on coding style because he prefers arrows function declaration:

const sum = (a, b) => a + b;

And I prefer old-style standalone function declaration:

function sum(a, b) {
    return a + b;
}

My point is that code in old-style more readable and you can more clearly distinguish function and variable declarations. His point is that code with arrow functions just run faster.

Do you know something about actual performance penalties (in v8) when you use old-style standalone function declaration instead of arrow functions? Are that penalties really exists?

Upvotes: 115

Views: 37987

Answers (8)

SalemC
SalemC

Reputation: 38

I'd agree with jmrk's answer here but am reinforcing Rohan's answer.

It's worth noting that arrow functions are not only "syntactic sugar" when used in ES6 classes.

Arrow functions in classes aren't present on the prototype, but are created as a member for every object, every time that object's class is instantiated.

For example, take this class:

class ArrowFunctionMember {
    i = 0;

    test = () => {
        this.i += 1;
    }
}

That's the equivalent of doing:

class ArrowFunctionMemberEquivalent {
    i = 0;

    constructor () {
        this.test = function () {
            this.i += 1;
        }
    }
}

It's much easier to spot what's going on in the second example - When the class is instantiated an instance of the test function is created with it, this can lead to much larger memory consumption (and will be inherently slower to instantiate) depending on how many objects are created.

Here's a test I made to illustrate the performance difference between instantiation speed of classes with arrow function members vs with regular function members.

So if you're not creating many objects from classes with arrow function members, the performance difference will likely be negligible. However, if you are creating a large amount of objects then consider using regular member functions instead, so you can take advantage of the prototype sharing that JavaScript objects use.

Upvotes: 1

bukso
bukso

Reputation: 1376

I made a short benchmark in jsben.ch. I ran it many times it seems that arrow functions were in the most cases just tiny little bit faster than normal functions. Even once or twice normal function was faster... It looks like the difference is insignificant. So in short - if you don't need to mind context or this, just use whatever looks better for you ;)

https://jsben.ch/kJxPT

const a = (b, c) => b+c;

a(1,2);

VS

function a(b,c){
    return b+c;
}

a(1,2);

enter image description here

Upvotes: 6

dannyxnda
dannyxnda

Reputation: 1014

An arrow function is just a function expression. The below are equal:

const foo = (a, b) => a + b // foo = an anonymous function
const foo = function(a, b) { return a + b; }
const foo = new Function("a", "b", "return a + b")

A function declaration can be hoisted:

function foo(a, b) { return a + b; }

An arrow function cannot be use as an generator function like:

function* foo(a, b) {
  yield a;
  yield b;
}

Consider to use them when your functions need this keyword.


There are at least not many differences in the performance.

Upvotes: 0

Rohan Veer
Rohan Veer

Reputation: 1490

I think arrow functions in class properties might cause some performance issue. Here is an example :

class Car {
  setColor = (color) => { this.color = color; }

  constructor() {
     this.color = '';
     this.getColor = () => { return this.color; };
  }

  printCarColor() {
     console.log(this.color);
  }
}
var c = new Car();
console.log(c);

If we take a look at the variable c you will notice that function setColor and getColor are created brand new for each instance, and each new copy is placed on each instance whereas function printCarColor is residing on the prototype.

If you want a thousand instances to each be able to make fixed-context method references, you're going to need a thousand separate methods (not one shared), and of course then you're going to have to store each of those thousand separate methods on the instances themselves, thereby defeating the whole point of the single shared prototype.

Upvotes: 12

Alex D.
Alex D.

Reputation: 19

There are two examples for nodejs:

function testFat(a, b) {
    return a + b;
}

let testArrow = (a, b) => a + b;

let t1 = process.hrtime();
let tmp1 = 0;
for (let i = 0; i < 1000000000; ++i) {
    tmp1 = testFat(tmp1, i);
}
var fatTime = process.hrtime(t1);
console.log('fat', fatTime);

let t2 = process.hrtime();
let tmp2 = 0;
for (let i = 0; i < 1000000000; ++i) {
    tmp2 = testArrow(tmp2, i);
}
var arrowTime = process.hrtime(t2);
console.log('arrow', arrowTime);
function testFat() {
    return 0;
}

let testArrow = () => 0;

let t1 = process.hrtime();
for (let i = 0; i < 1000000000; ++i) {
    testFat();
}
var fatTime = process.hrtime(t1);
console.log('fat', fatTime);

let t2 = process.hrtime();
for (let i = 0; i < 1000000000; ++i) {
    testArrow();
}
var arrowTime = process.hrtime(t2);
console.log('arrow', arrowTime);```

Results are:

bash-3.2$ node test_plus_i.js

fat [ 0, 931986419 ]

arrow [ 0, 960479009 ]

bash-3.2$ node test_zero.js

fat [ 0, 479557888 ]

arrow [ 0, 478563661 ]

bash-3.2$ node --version

v12.8.0

bash-3.2$

So you can see that there is no difference in function call overhead.

Upvotes: 1

jmrk
jmrk

Reputation: 40521

V8 developer here. Arrow functions are (mostly) just "syntactic sugar" for conventional function declarations. There is no performance difference.

Upvotes: 238

Lokii
Lokii

Reputation: 482

in my exp I have found that arrow functions do run faster than normal JS functions. Here is a small snippet in react which uses arrow and normal function. I found that the component using arrow functions runs a bit faster than the one having normal js function.

https://codepen.io/lokeshpathrabe/pen/qgzadx

class Fun extends React.Component {

  constructor(props){
    super(props);
    this.state = {start: new Date().getTime(),
                 end: new Date().getTime(),
                 number: 0};
    console.log('Function start: ', this.state.start);
    const fun = function(me){
      let n = me.state.number
      me.setState({
        ...me.state, end: new Date().getTime(), number: ++n
      })
    }
    this.interval = setInterval(fun, 1, this);
  }

  stop(){
    clearInterval(this.interval);
  }

  componentDidUpdate(){
    if((this.state.end - this.state.start) > 5000){
      console.log('Function end: ', this.state.end);
      clearInterval(this.interval)
    }
  }

  render() {
    return (
      <div>
        <h2>Counter with Function {this.state.number}</h2>
      </div>
    )
  }
}

class Arrow extends React.Component {

  constructor(props){
    super(props);
    this.state = {start: new Date().getTime(),
                 end: new Date().getTime(),
                 number: 0};
    console.log('Arrow start: ', this.state.start);
    this.interval = setInterval(()=>{
      let n = this.state.number
      this.setState({
        ...this.state, end: new Date().getTime(), number: ++n
      })
    }, 1);
  }

  stop(){
    clearInterval(this.interval);
  }

  componentDidUpdate(){
    if((this.state.end - this.state.start) > 5000){
      console.log('Arrow end: ', this.state.end);
      clearInterval(this.interval)
    }
  }

  render() {
    return (
      <div>
        <h2>Counter with Arrow {this.state.number}</h2>
      </div>
    )
  }
}

class HOC extends React.Component {

  render() {

    return (<div>
        <h1>The one reaching higher count wins</h1>
        <Arrow/>
        <Fun/>
        </div>);
  }
}

ReactDOM.render(<HOC />, document.getElementById('react-content'))

Do let me know if your opinion differ

Upvotes: 0

Ben Aston
Ben Aston

Reputation: 55739

The following shows that:

  1. There is a penalty for going first (either traditional or fat)
  2. There is no discernible difference in Chrome

function goFat() {
    for (var i = 0; i < 1000000; i++) {
        var v = ()=>{};
        v();
    }
}

function goTraditional() {
    for (var i = 0; i < 1000000; i++) {
        var v = function() {};
        v();
    }

}

function race() {
  var start = performance.now();
  goTraditional();
  console.log('Traditional elapsed: ' + (performance.now() - start));
  start = performance.now();
  goFat()
  console.log('Fat elapsed: ' + (performance.now() - start));
  start = performance.now();
  goTraditional();
  console.log('Traditional elapsed: ' + (performance.now() - start));
  start = performance.now();
  goFat()
  console.log('Fat elapsed: ' + (performance.now() - start));
  console.log('------');
}
<button onclick="race()">RACE!</button>

Upvotes: 5

Related Questions