Prototype bind() Performance


[UPDATE: 2009-03-11 – Noticed a bug in the test code and had to redo all the tests.]
[UPDATE: 2009-03-11 – Refactored test code and included trunk variant from Tobie Langel (core Prototype team member)]
[UPDATE: 2009-03-12 – Added tests for Kangax’s solution, added “Improved” test – a hybrid of Kangax+Broofa]

I recently proposed an alternate implemenation to Prototype’s Function#bind() method over on the Prototype Group.  This prompted a number of people to reply, including several who, rightly, asked if I had any hard data showing that this alternate implementation showed real performance gains.  To test this, I’ve once again dipped into the JSLitmus well and created the Prototype bind() Performance Test.  This test evaluates the following bind() implementations:

  • “1.6.0.3” – bind() as implemented in the latest stable Prototype release
  • “trunk” – bind(), as implemented in the trunk of the Prototype source tree
  • “Tobie’s” – a revised Prototype trunk implementation provided by Prototype team member, Tobie Langel
  • “Broofa’s” – the implementation I proposed
  • “Kangax’s” – using optimized call/apply branch
  • “Improved” – Kangax approach + Broofa’s arg array optimization

For each approach, I test three cases: binding an object to a function (shown as “…(obj)”),  binding an object + two arguments (shown as “…(obj, 1, 2)”), and binding an object +two arguments and passing two arguments (shown as “…(obj, 1, 2 [,3, 4])”)

The results (below) show anywhere from a 2x to 15x performance improvement, depending on platform and test case.

As with previous tests, there are a couple points worth calling out:

  • This is not testing the performance of binding a function – only of invoking an already-bound function.  (I assume that binding is a relatively rare operation where performance is not as important)
  • The function being bound in this test is an empty function, which exaggerates the performance differences here.  That is by intent – I wanted to examine the performance of the code required to support the bind operation.
  • I’m  at somewhat of a loss as to how to explain the dramatic difference on FF between “(obj)” and “(obj, 1, 2)” for the “Broofa” test.  (Is trying to access ‘arguments’ when no arguments are defined slower than if arguments are defined???)
  • Method call performance is a big factor in this.  Inline code can be dramatically faster than a method call if the method isn’t doing much. (… It looks like the main improvement in performance is the reuse of the arguments array, not the elimination of function calls.  And here I thought I knew what I was talking about :P)
  • … similarly, if you’re bind()’ing a method that is fast, e.g. an accessor like, “function() {return this.foo;}”, you’re likely reducing the performance of that call by a factor of 5-10x.

As always, you’re invited to view the source of the JSLitmus test above for further comments and details on how the test is implemented.



3 responses to “Prototype bind() Performance”

  1. Turns out your proposed implementation actually avoids creating an extra array on each function call. So I suspect the biggest gain happens there, not in avoiding function calls.

  2. Ah, good point. I knew I put that in there for a reason. 😉

    On Firefox, it looks like Array creation takes about 3x longer than calling a function, btw. ‘Haven’t tested other platforms.

  3. Not only is Array creation probably a lot slower than a function call… theere’s alos a lot more object created, thus more frequent and longer garbage collection times.