Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda functions vs bind, memory! (and performance)

I would like to determine which is the best practice between equivalent solutions. The use case is an instance of a class that listen to an event. Dr. Axel Rauschmayer prefers the lambda for readability. I agree with him. But in term of performance and memory consumption, which is the best?

With a lambda function

class Abc {   constructor() {     let el = document.getElementById("my-btn")     if (el)       el.addEventListener("click", evt => this.onClick(evt))   }   onClick(evt) {     console.log("Clicked!", evt.target)   } } 

Can someone to confirm or infirm if the local variables (here el) can't be cleared by the garbage collector? Or, are modern browsers capable to detect they are unused in the closure?

With Function.prototype.bind:

class Abc {   constructor() {     let el = document.getElementById("my-btn")     if (el)       el.addEventListener("click", this.onClick.bind(this))   }   onClick(evt) {     console.log("Clicked!", evt.target)   } } 

There is no memory issue, but all benchmarks suggest that bind is far slower than a closure (an example here).

EDIT: I don't agree with the comments that ignore the performance issue of bind. I suggest to read this answer with the code of the implementation in Chrome. It cannot be efficient. And I insist: all the benchmarks I saw, show similar results on all browsers.

Is there a way to have a low memory usage and a good performance at the same time?

like image 875
Paleo Avatar asked Feb 08 '17 16:02

Paleo


People also ask

Are lambdas faster than functions?

Being anonymous, lambda functions can be easily passed without being assigned to a variable. Lambda functions are inline functions and thus execute comparatively faster.

How much memory should I allocate to Lambda?

You can configure the amount of memory allocated to a Lambda function, between 128 MB and 10,240 MB. The Lambda console defaults new functions to the smallest setting and many developers also choose 128 MB for their functions.

How do I speed up my AWS Lambda processor?

Adding more memory proportionally increases the amount of CPU, increasing the overall computational power available. If a function is CPU-, network- or memory-bound, then changing the memory setting can dramatically improve its performance.


1 Answers

Closures (or arrow functions, aka lambdas) don't cause memory leaks

Can someone to confirm or infirm if the local variables (here el) can't be cleared by the garbage collector? Or, are modern browsers capable to detect they are unused in the closure?

Yes, modern JavaScript engines are able to detect variables from parent scopes that are visible from a closure but unused. I found a way to prove that.

Step 1: the closure uses a variable of 10 MB

I used this code in Chromium:

class Abc {     constructor() {         let arr = new Uint8Array(1024*1024*10) // 10 MB         let el = document.getElementById("my-btn")         if (el)             el.addEventListener("click", ev => this.onClick(ev, arr))     }     onClick(ev) {         console.log("Clicked!", ev.target)     } }  new Abc() 

Notice the variable arr of type Uint8Array. It is a typed array with a size of 10 megabytes. In this first version, the variable arr is used in the closure.

Then, in the developer tools of Chromium, tab "Profiles", I take a Heap Snapshot:

Snapshot 1: the variable <code>arr</code> is used in the closure

After ordering by decreasing size, the first row is: "system / JSArrayBufferData" with a size of 10 MB. It is our variable arr.

Step 2: the variable of 10 MB is visible but unused in the closure

Now I just remove the arr parameter in this line of code:

            el.addEventListener("click", ev => this.onClick(ev)) 

Then, a second snapshot:

Snapshot 2: the variable <code>arr</code> is not used in the closure

The first row has vanished.

This experience confirms that the garbage collector is capable to clean variables from parent scopes that are visible but unused in active closures.

About Function.prototype.bind

I quote the Google JavaScript Style Guide, section on arrow functions:

Never call f.bind(this) or goog.bind(f, this) (and avoid writing const self = this). All of these can be expressed more clearly and less error-prone with an arrow function. This is particularly useful for callbacks, which sometimes pass unexpected additional arguments.

Google clearly recommends to use lambdas rather than Function.prototype.bind.

Related:

  • Why is bind slower than a closure?
  • A benchmark
  • Arrow functions vs. bind() from Dr. Axel Rauschmayer

like image 75
Paleo Avatar answered Sep 20 '22 17:09

Paleo