Why is Function.prototype.bind slow?

It's impossible to implement a fully-featured bind in ES5 alone. In particular sections 15.3.4.5.1 through 15.3.4.5.3 of the spec cannot be emulated.

It's impossible to implement a fully-featured bind in ES5 alone. In particular sections 15.3.4.5.1 through 15.3.4.5.3 of the spec cannot be emulated. 15.3.4.5.1, in particular, seems like a possible performance burden: in short bound functions have different Call internal properties, so calling them is likely to take an unusual and possibly more complicated code path.

Various other specific un-emulatable features of a bound function (such as arguments/caller poisoning, and possibly the custom length independent of original signature) could possibly add overhead to each call, although I admit it's a bit unlikely. Although it looks like V8 doesn't even implement the poisoning at the moment. EDIT this answer is speculation, but my other answer has something more approaching evidence.

I still think this is valid speculation, but it's a separate answer, so I'll leave it as such and just refer you to the other one.

Based on jsperf.com/bind-vs-emulate/6, which adds the es5-shim version for comparison, it looks like the culprit is the extra branch and instanceof that the bound version has to perform to test if it's being called as a constructor. Each time the bound version is run, the code that gets executed is essentially: if (this instanceof bound) { // Never reached, but the `instanceof` check and branch presumably has a cost } else { return target. Apply( that, args.

Concat(slice. Call(arguments)) ); // args is in your case. // So the cost is: // * Converting (empty) Arguments object to (empty) array.

// * Concating two empty arrays. } In the V8 source code, this check appears (inside boundFunction) as if (%_IsConstructCall()) { return %NewObjectFromBound(boundFunction); } (Plaintext link to v8natives. Js for when Google Code Search dies.) It is a bit puzzling that, for Chrome 16 at least, the es5-shim version is still faster than the native version.

And that other browsers have rather varying results for es5-shim vs. native. Speculation: maybe %_IsConstructCall() is even slower than this instanceof bound, perhaps due to crossing native/JS code boundaries. And perhaps other browsers have a much faster way of checking for a Construct call.

Added instanceof check to raynosBound. I think the overhead is mainly concating empty arrays. Do you think its worthwhile to hand optimise the ES5 bind shim for the args.

Length === 0 case to return a function that just does target. Apply(that, arguments)? – Raynos Jan 7 at 3:23 Personally I think any optimization here is microoptimization, and I would wait until my benchmarks showed that bound functions were outpacing e.g. Network latency in causing my app to be slow before considering anything of the sort.

– Domenic Jan 7 at 7:14.

The V8 source code for bind is implemented in JS. The OP doesn't emulate bind because it doesn't curry arguments the way bind does. Here is a fully featured bind: var emulatebind = function (f, context) { var curriedArgs = Array.prototype.slice.

Call(arguments, 2); return function () { var allArgs = curriedArgs. Slice(0); for (var I = 0, n = arguments. Length; I Push(argumentsi); } return f.

Apply(context, allArgs); }; }; Obviously, a quick optimization would be to do return f. Apply(context, arguments); instead if curriedArgs. Length == 0, because otherwise you have two unnecessary array creations, and an unnecessary copy, but perhaps the native version is really implemented in JS and does not do that optimization.

Caveat: This fully featured bind does not correctly handle some corner cases around this argument coercion in strict mode. That might be another source of overhead.

It doesn't emulate bind fully. But the performance tests only use the subset of the parts of bind that are emulated. Can you explain why the parameter currying causes an overhead when it's not used in the performance tests?

Can you edit the tests with the fully featured one? – Raynos Jan 6 at 19:36 Performance difference still exists – Raynos Jan 6 at 19:41 @Raynos, added a link to the JS source code for the bind function from v8natives.js. – Mike Samuel Jan 6 at 19:49 Hm, why not var newArgs = .slice.

Call( arguments ); and then f. Apply( context, curriedArgs. Concat( newArgs ) );... – Šime Vidas Jan 6 at 19:52 You linked unit tests rather then implementation source code.

Its useful to link both. – Raynos Jan 6 at 19:54.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions