Why Is Bind Slower Than a Closure

Why is bind slower than a closure?

Chrome 59 update: As I predicted in the answer below bind is no longer slower with the new optimizing compiler. Here's the code with details: https://codereview.chromium.org/2916063002/

Most of the time it does not matter.

Unless you're creating an application where .bind is the bottleneck I wouldn't bother. Readability is much more important than sheer performance in most cases. I think that using native .bind usually provides for more readable and maintainable code - which is a big plus.

However yes, when it matters - .bind is slower

Yes, .bind is considerably slower than a closure - at least in Chrome, at least in the current way it's implemented in v8. I've personally had to switch in Node.JS for performance issues some times (more generally, closures are kind of slow in performance intensive situations).

Why? Because the .bind algorithm is a lot more complicated than wrapping a function with another function and using .call or .apply. (Fun fact, it also returns a function with toString set to [native function]).

There are two ways to look at this, from the specification point of view, and from the implementation point of view. Let's observe both.

First, let's look at the bind algorithm defined in the specification:

  1. Let Target be the this value.
  2. If IsCallable(Target) is false, throw a TypeError exception.
  3. Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.

...

(21. Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.

(22. Return F.

Seems pretty complicated, a lot more than just a wrap.

Second , let's see how it's implemented in Chrome.

Let's check FunctionBind in the v8 (chrome JavaScript engine) source code:

function FunctionBind(this_arg) { // Length is 1.
if (!IS_SPEC_FUNCTION(this)) {
throw new $TypeError('Bind must be called on a function');
}
var boundFunction = function () {
// Poison .arguments and .caller, but is otherwise not detectable.
"use strict";
// This function must not use any object literals (Object, Array, RegExp),
// since the literals-array is being used to store the bound data.
if (%_IsConstructCall()) {
return %NewObjectFromBound(boundFunction);
}
var bindings = %BoundFunctionGetBindings(boundFunction);

var argc = %_ArgumentsLength();
if (argc == 0) {
return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
}
if (bindings.length === 2) {
return %Apply(bindings[0], bindings[1], arguments, 0, argc);
}
var bound_argc = bindings.length - 2;
var argv = new InternalArray(bound_argc + argc);
for (var i = 0; i < bound_argc; i++) {
argv[i] = bindings[i + 2];
}
for (var j = 0; j < argc; j++) {
argv[i++] = %_Arguments(j);
}
return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
};

%FunctionRemovePrototype(boundFunction);
var new_length = 0;
if (%_ClassOf(this) == "Function") {
// Function or FunctionProxy.
var old_length = this.length;
// FunctionProxies might provide a non-UInt32 value. If so, ignore it.
if ((typeof old_length === "number") &&
((old_length >>> 0) === old_length)) {
var argc = %_ArgumentsLength();
if (argc > 0) argc--; // Don't count the thisArg as parameter.
new_length = old_length - argc;
if (new_length < 0) new_length = 0;
}
}
// This runtime function finds any remaining arguments on the stack,
// so we don't pass the arguments object.
var result = %FunctionBindArguments(boundFunction, this,
this_arg, new_length);

// We already have caller and arguments properties on functions,
// which are non-configurable. It therefore makes no sence to
// try to redefine these as defined by the spec. The spec says
// that bind should make these throw a TypeError if get or set
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
// TODO(lrn): Do set these to be thrower.
return result;

We can see a bunch of expensive things here in the implementation. Namely %_IsConstructCall(). This is of course needed to abide to the specification - but it also makes it slower than a simple wrap in many cases.


On another note, calling .bind is also slightly different, the spec notes "Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties"

Function.bind vs Closure in Javascript : how to choose?

Take a look at this line in the example in the link above

console.log(self.myName, this.myName);

(with self = this; a couple of lines above). The closure defined outerFunction method, exists in a different scope that is why it has a different this value from the outerObj object. (self.myName!=this.myName)

Scope traversal means, when you are reaching to grab a value (variable,object) that exists in a different scope, therefore additional overhead is added (code becomes slower to execute).

Using bind, you 're calling a function with an existing scope, so that scope traversal does not take place.

Is it right to avoid closures using bind in JavaScript?

I would suggest this:

var oControl = new Control({
click: this.performAction.bind(this)
});

There appears to be no reason in your code for the self variable at all and if the click handler is just going to call your other method, then you may as well use the .bind() without the wrapper function.

FYI, .bind() creates a closure itself so don't be thinking that using .bind() is eliminating a closure. It is eliminating you having to hand-code a closure variable which is what makes it handy to use and makes your code look cleaner.

As for your other questions:

  1. Are closures too bad for browser's memory?

Closures do use some additional memory. Unless you have a zillion of them, that extra memory is not likely material. And, .bind() likely also uses a closure in its implementation (the this pointer has to be stored somewhere).


  1. Is avoiding closures using bind in JavaScript a good way?

.bind() is very useful and you should feel free to use it when it serves your purpose. Whether to use your first block of code with your own closure variable, your second block of code with a wrapper function using .bind() or my suggestion is largely a matter of opinion on coding style and opinion on cleanliness of implementation. All can work fine and there is unlikely to be a meaningful difference in performance or memory usage.

Does using 'bind' when returning a function creates a closure?

when y() is invoked, does it has a closure over x because of bind?

No, calling bind on a function returns a bound function. This bound function might however closure the function and the arguments, but that depends on the implementation. An implementation with a closure would look like:

 Function.prototype.bind = function(context, ...args) {
const bound = this;
return function(...args2) { // the closure
bound.call(context, ...args, ...args2);
};
};

Closure or Bind

In most cases, they will function identically. However...

If you ever start to actually use the value of this, the function returned by limiter1 will be unbound (so a consumer could change the value with a call to Function.prototype.bind). In limiter2, it's locked down with the initial bind call.

Also, they use different levels of scope to get the limiter variable. Depending on the engine, you could have a (minute) difference in performance.

Difference between Function Binding and Closure in Javascript?

It probably depends a little on which should be preferred. I tend to use the latter (though actually I prefer the former, but some 3rd party libraries we're using limit that). I think the important thing on picking a style is being consistent.

A note for the prototype.bind is that it's not supported by IE8 and below which might cause you a problem.

I think performance wise, I'd expect bind to be a little bit slower as you're calling an extra function in there, but it'll probably depend on browser optimizations. I'll try putting together a jsperf example when their site comes back up to answer that part of the question though.

update

Seems JSPerf isn't going to be up anytime soon. Here's an snippet that I've put together that shows the closure was quicker (assuming I've done it correct). The closure was slightly more than 7x faster. If you run with the console open you'll see the timings.

var limit = 100000;
var a = { val: 0, do: function(i) { val = i; /* Actually do some work to ensure doesn't get optimised out */ } };
var b = { myFunc: function(callback) { callback(); /* Function that's going to change this keyword */} };

var start = +new Date();
for(var i = 0; i < limit; i++) { b.myFunc(function() { this.do(i); }.bind(a)); };
var end = +new Date();var diff = end - start;console.log("bind took " + diff + " ms");
var start = +new Date();
for(var i = 0; i < limit; i++) { var that = a; b.myFunc(function() { that.do(i); }); };
var end = +new Date();var diff = end - start;
console.log("closured took " + diff + " ms");

Bound function instead of closure to inject extra arguments

It's not a "closure", it's just an anonymous function.

Personally I prefer the bind version because as you say, it's more concise. However, according to this jsperf (http://jsperf.com/anonymous-function-vs-bind), it's ten times slower, which surprises me greatly, especially since the bind used here seems to be the native one. One hypothesis is that bind, or rather the function it generates, needs to do work around looking at the arguments passed in and constructing an argument list to pass along to the function being called.

To maintain this, you need a variant of bind such as Underscore's _.partial, or you could write one yourself:

function partial(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
return fn.apply(this, args.concat(slice.call(arguments, 1)));
};
}

Unfortunately, the variation using partial ({ onClick: partial(someHandler, 'clicked'); }) is still ten times slower than the anonymous function.

The hypothesis that argument list handling is causing the slowdown is supported by another test case in the jsperf, which defines a partial1 which predefines just the first of exactly two arguments to the underlying function:

function partial1(fn, a) {
return function(b) {
return fn.call(this, a, b);
};
}

Using that one, which doesn't have to create and merge argument lists, results in a slowdown of only 25-35%, instead of 90%.

If we don't care about passing through this, which allows us to avoid using Function#call:

function partial2(fn, a) {
return function(b) {
return fn(a, b);
};
}

Then the slowdown is just 10%.

However, if we really want to pass through this, then we need to write the anonymous function version as

{ onClick: function(event) { someHandler.call(this, 'clicked', event); }  }

which also results in a 20-25% slowdown from the original version, presumably due to the cost of invoking Function#call. So in that sense, asusming you do want to pass through this, the performance of the anonymous function and our home-grown partial1, customized for number of arguments, is roughly equivalent, which is not surprising since they're essentially doing identical work.

Lambda functions vs bind, memory! (and performance)

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



Related Topics



Leave a reply



Submit