One area of the Prototype JavaScript library that I have a bit of a love-hate relationship with is its support for mimicing OO inheritance. The ability to call $super from within a function to refer to a superclass’ implementation is pretty darn cool, but I’ve found myself more and more annoyed at having to navigate what seem like unnecessarily deep and complicated stack traces when trying to debug code. It was while mired in the bowels of Class.create() and Class#addMethods() that I found myself wondering how much of a performance penalty this stuff was incurring. To find out, I put together a test to determine how the different strategies for emulating OO inheritance in JavaScript performed. Here’s what I tested:
- Ad hoc inheritance – This is a common(?) homebrew technique for allowing prototypes to leverage the code in objects further up the prototype-food chain. Methods are overridden by keeping a reference to the parent method in a separate property , which can then be invoked as needed. It’s fast but not very pretty, and it’s arguable whether or not this qualifies as real “OO” inheritance.
- Prototype-style inheritance – Prototype uses a strategy inspired by Alex Arenell’s Inheritance library. Subclass methods declare a “$super” argument that is set up by Prototype to reference the superclass’ method.
- Base2-style inheritance – Dean Edwards’ library. Subclass methods invoke “this.base()” to call their superclass’ implementation.
- John Resig inheritance – JR, of jquery fame, experimented with a Base2 variant which he published on his blog. It’s a bit simpler than Base2, but seemed worth testing.
- [Update] MooTools – For you MooTools fans out there, I believe that library uses the same approach that Dean Edwards came up with for Base2, so performance should be similar. aNieto2K links to his test in the comments, below, if you’d like to verify this for yourself. (I’d add this to the test, but Prototype and Moo collide over the use of the ‘Class’ name)
Tests were performed by using JSLitmus to create a Inheritance Performance testbed. In it, I create a base class and subclass using each of the above approaches. Each base class has a single method, “foobar” which is overridden, and invoked by, the corresponding subclass. The rate at which objects could be instantiated for each base class and subclass was tested. The rate at which a method could be invoked on the base classes and subclasses was also tested. Here are the results (first three are on MacBook – the IE and Chrome tests are on a Dell laptop):
There are pros and cons to each technique. For sheer balls-out performance you’re best off using the ad-hoc “move aside” approach. That’s only really important if you’re making 100,000’s 1,000s of calls per second to overridden methods, however. Both Base2 and Resig’s approach have decent invocation performance, but Base2 can be a bit slow at object creation.
The most interesting result was the utter crap-tastic performance of Prototype. When calling methods that use $super it’s consistently 20x slower than the other solutions. (Likely a result of the additional closure functions it requires). Regardless, this is definitely something to watch out for for any application that makes heavy use of subclassing. Or, rather, of subclassed methods.
28 responses to “JavaScript Inheritance Performance”
[…] Kieffer has run some benchmarks on the performance of JavaScript inheritance using different inheritance […]
I’m missing prototypical inherritance in the benchmark. More as an argument to stop trying to make JS look like Java and just use the prototypical OO.
myClass = function(){}
myClass.prototype = {myMethod:function(name){
alert(name)
}}
myClass2 = function(){}
myClass2.prototype = myClass.prototype;
myClass2.prototype.myMethod = function(name){
/* override */
myClass.prototype.myMethod.apply(this,[“hello “+name])
}
Or use Object.beget from Douglas Crockford.
Oops, following code is wrong:
myClass2.prototype = myClass.prototype;
myClass2.prototype = Object.beget(myClass.prototype)
is needed or myClass.prototype methods gets overwritten as well.
I change Prototype for MooTools in ths chart and the results are more interesting
http://www.anieto2k.com/demo/mooclass/
[…] Kieffer has run some benchmarks on the performance of JavaScript inheritance using different inheritance […]
@Ben: Thanks for the suggestion. That’s an obvious (and interesting) test that I should have included. I’ve created a 2nd test that tests this (and that removes the fairly uninteresting results for calls to the parent class.) Here’s the results I get for FF3 on MacOSX:
As you can see, the apply() technique is a bit better than the other libraries, but significantly slower than the AdHoc method. (I wish I could claim to have known it would be and that’s why I didn’t test it, but the truth is that I was expecting it to be w/in 70-80% of the speed of the direct call. *dooh!*)
@aNieto2K: Note MooTools is using the same basic technique as Base2 and John Resig’s solution. Performance seems to be comparable (right?) If you’re results are significantly different, please feel free to post the tinyurl for your JSLitmus results here.
Performance depends on level of inheritance.
I created 5 classes for Base2, John Resig’s solution and for my own. I added object initializing methods for each class:
http://beatle.joos.nnov.ru/inherit/
All classes looks like:
var Resig_Level4 = Resig_Level3.extend({
foobar: function() {
return this._super();
},
init: function() {
this._super();
}
});
Each ChildClass_Level[N+1] extends ParentClass_Level[N] class and overrides initializing method and foobar method.
Here’s the results:
Results: http://tinyurl.com/b369d2
That instantiating the ApplyClass is worse then the AddHoc class is due to having more bits to make up the class. So we see that Prototype and Base2 create pretty chunky classes.
We also see that taking the super out of the Main Class prototype removes initializing overhead in the subclass, however, this comes at a tradeoff for super method calls.
ResigClass, Base2, Prototype all depend on apply for method (re)scoping, so I am not suprised to see very similar results with the ApplyClass.
The AddHoc class turns the super into a property of the subclass, which is simply blazingly fast to reference.
The main performance bog seems to come from the need to (re)scope super methods.
Summary:
– reduce bits of subclasses in classing techniques.
– make the super a property of your class if you need high performance method calls.
– use apply method on super methods if you need high performance subclass instantiation (at cost of method call performance).
It bothers me that performance is being benchmarked against code Resig played with but isn’t actually in use in production. If jQuery were to use Resig’s content and encounter use cases that dictated that they add functionality they would very likely have different results than this theoretical example. When you run benchmarks against the other methodologies listed here you are testing more than just inheritance (assuming that most of the initialization mythologies apply any additional logic beyond what’s necessary for inheritance to support additional extensibility).
If you really wanted to test only inheritance then each framework would need to be cleansed of any code that facilitates additional code that does anything else. Assuming that no one is going to do that, I’m inclined to take Resig’s code example as an academic pursuit, and not something that’s designed for production and tested against the use cases that such could would endure.
@Aaron: Yeah, I suppose you make a valid point. Had I the time (and inclination), however the line between what constitutes an academic exercise and what a real-world implementation is can be a bit blurry. I took a good hard look at Resig’s code and one reason I decided to include it in the test is that it was the solution that I found the most attractive. While it doesn’t address all of the nuanced requirements that shaped Dean Edwards solution, it does the job just fine and performs noticeably better. Also, Resig is notable enough in our field that it seemed worth calling out.
Feel free to play with JSLitmus and put some tests of your own together by the way. It’s trivially easy to use, and I’d be more than happy to compare notes, post a follow-up, and even see if Ajaxian would want to post the work as well.
@Covex: Nice call out on the inheritance levels. It makes sense given the overhead required to pass control and variable scope between inheritance level. Thanks for posting that.
[…] was a post about benchmarking inheritance methods that was pretty interesting (here’s the post that Ajaxian was covering). In it, various methods for extending objects in JavaScript are […]
Hi broofa,
I like your article, however, I agree with Aaron that using John Resig’s Class is a bit unfair. It doesn’t do half the stuff that mootools and prototype do and it’s broken/not complete. In IE it will break if you use a method name that mirrors those with the DontEnum attribute (mootools has the same error). Also it doesn’t return the correct constructor. Both simple fixes, but I bet folk grab that code as it appears to be the fastest and then will run in to problems.
Aarons comment also seems a bit unfair to me:
“and not something that’s designed for production and tested against the use cases that such could would endure.”
Because the mootools class also has a bug and it is used in production.
I’ve uploaded another test similar to yours that also tests for the above problems, letting you know if they “Passed” or “Failed”. I’ve also included in the tests my own Class implementation which I’ve been using for a while now and it seems to perform the best, this is due to the way I do parent method calling. It also does most of what the mootools class does, but as mentioned, it doesn’t have a library based on it so it’s not a fair comparison.
http://www.projectcss.net/oop-test/
I see what you were doing with this article and I really like it. Comparing the OOP implementations used by the OOP frameworks could lead to extra performance, and it sure beats looking at more selector performance results lol
[…] las pruebas realizadas por Broofa, vimos que los resultados daban como ganador al script de John Resig que dejaba a los demás a la […]
I’m sitting here wondering why you would ever want to call a parent’s method from within an overriding method. It seems like if you need to do something that convoluted, you’re doing something wrong.
I’d rather use the method Doug Crockford outlines as parasitic inheritance. You can’t call a parent method from within an overriding method, it’s a little slower on instantiation, but runs par with parent method invocation. It also makes for much cleaner code, being able to pass parameters into the parent class creation, and allowing for private members via closures.
@Jonathan – I would hardly describe needing to invoke a parent method implementation as, “convoluted”. It’s a tried and true pattern that is ubiquitous in other languages. And a classic method for providing code reuse.
One problem with parasitic inheritance is that it doesn’t provide a simple way for subclasses to inject behavior into super classes. For example, if a subclass needs to add a “onAfterFoo” callback to the foo() method of a superclass, how is that accomplished with parasitic inheritance?
With classic inheritance, the subclass need only define a foo() method that looks something like this:
function() {
this.parent.foo();
this.onAfterFoo();
}
But with parasitic inheritance you have to cobble together some way of preserving a reference to the parent implementation before overriding the foo() method. And, to date, I have yet to see an elegant solution to that problem that doesn’t look a lot like the classic inheritance solutions you feel are wrong.
[…] The tests labeled Parasitic are using the JavaScript Inheritance method outlined in my previous post. The other labels are described originally at Broofa.com’s article on Javascript inheritance performance: […]
[…] I found a great article that compares inheritance performance of different libraries, here are results with directly called parent method approach ( using vClass […]
Just FYI, using tinyurls in an image src is not a good idea. Some people (like me) have a preference cookie from tinyurl.com, which will load the redirect page at preview.tinyurl.com instead of redirecting to the original URL. The redirect page is HTML, and so the images in your benchmark won’t show up.
nmishbektjjs
Hello guys.
I have also wrote one classical iheritance implementation 🙂 There is a lot of them, I know, but I like my way more 🙂
The most important points of my implementation are:
1. User will work with constructor to create a class, not with object – private class variables and functions are possible.
2. I think at the moment when browser rendering any constructor it hasn’t to initialize all the stuff the constructor contains
3. I can use more classical order pattern inside of the constructor. (first private variables, then privileged, then public methods and then private methods)
4. access overwritten methods via _super
5. Pass any variables to constructor, so they can be used everywere in the class, without to have to map over them, like if you do it over init method
Speedtest shows that my implementation is slower than j3Class or wr Class, but it still much faster than all other famous implementations.
Probably you have some Ideas how I can impove the performance without to change the usability?
http://dev.ajaxsoft.de/classtest/
@Oleg Slobodskoi from your tests it results that is not faster than Base2 and Dojo. Whith what other implementations did you compared?
well, here are results on my mac and FF 3.5.5:
My implementaion:
http://tinyurl.com/yeer83v
Dojo:
http://tinyurl.com/y9sykqd
Base:
http://tinyurl.com/yb47245
J3Class2:
http://tinyurl.com/yaphcyw
It variates from time to time, but if I test some rounds I see appr. this results.
@Michael .H you not?
@Oleg On my IE8 and FF 3.5 (Windows based) it did not performed as better as Dojo and Base2
Thanks for the testing samples. I was able to add my inheritance pattern to the list and got some interesting results (in the chart as App):
http://tinyurl.com/2fv9uqd
While instantiation was slower, the method calls were the fastest. I expected the slower instantiation because I do a mixin to preserve the constructor in a subClass’s prototype. But being faster on method calls was a nice surprise.
Inheritance is one method of code reuse in object-oriented languages, and Javascript has the power and flexibility to mimic classical inheritance quite effectively. But in trying to add classical inheritance to a language that doesn’t have it we may be adding rigidity and complexity without gaining much benefit.
I would agree with Jonathan that parasitic inheritance is a powerful code reuse pattern in Javascript, although I think that calling it “inheritance” isn’t very accurate. Words like “augmentation” and “composition” fit much better. I have heard the argument that parasitic inheritance is slow, but I have never seen any statistics that show meaningful differences between it and other techniques. For me, I find it to be a clean, easy, powerful way of reusing code.
@Broofa The way to call a “super” method would look like this:
var foo = obj.foo;
obj.foo = function() {
foo();
this.onAfterFoo();
}
If you really wanted to you could use a library like Underscore and call the .wrap() method: http://documentcloud.github.com/underscore/#wrap
Overall I think this is a great post. But I would argue that in most cases a parasitic, prototypal or functional approach is more powerful than trying to retrofit Javascript with classical inheritance. Crockford has some good articles and talks on this, located here:
http://javascript.crockford.com/inheritance.html (notice the comment at the bottom of the page)
http://yuiblog.com/crockford/ (Act III is really good)