Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Function.prototype.bind slow?

When comparing this benchmark with chrome 16 vs opera 11.6 we find that

  • in chrome native bind is almost 5 times slower then an emulated version of bind
  • in opera native bind is almost 4 times faster then an emulated version of bind

Where an emulated version of bind in this case is

var emulatebind = function (f, context) {     return function () {         f.apply(context, arguments);     }; }; 

Are there good reasons why there is such a difference or is this just a matter of v8 not optimizing enough?

Note: that emulatebind only implements a subset but that isn't really relevant. If you have a fully featured and optimised emulated bind the performance difference in the benchmark still exists.

like image 538
Raynos Avatar asked Dec 28 '11 12:12

Raynos


1 Answers

Based on http://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.

like image 55
Domenic Avatar answered Sep 29 '22 18:09

Domenic