JavaScript Memoization
Posted on February 25th, 2009 in JavaScript | 1 Comment »
I was taking a look at my friend Takashi’s JavaScript tweener which isn’t released yet and noticed he setup his code in a particular way for a few methods that get called dozens of times a second. He explained to me that it was for optimization through memoization. I ran a test case, and indeed it’s much faster. Check it out:
a = {}; a.deep = {}; a.deep.variable = { here: 3 } function plain(){ document.body.appendChild(document.createTextNode(a.deep.variable.here)); } function memoized(){ var z = a.deep.variable.here; return function(){ document.body.appendChild(document.createTextNode(z)); } } now = new Date(); for (var i = 0, max = 5000; i < max; i++){ plain(); } alert(new Date() - now); now = new Date(); for (var i = 0, max = 5000; i < max; i++){ memoized(); } alert(new Date() - now); // plain: 759 // memoized: 36
There’s a more complex example on the subject posted a month ago on Ajaxian and an easier to understand one on Oliver Steele’s blog written back in 2006.
One Response
That code does not test what you seem to think it tests. memoized does NOT do the same thing as plain in a much more efficient way – memoized returns a NEW FUNCTION which does the same thing as plain. To use the function as intended, you’d want to use this for your bottom loop:
m = memoized();
for(var i=0; i<5000; i++) {
m();
}
When you try it with just that modification, you will probably find that it does much WORSE than plain on its own, but that too is not strictly correct because your test methodology is terrible – most browsers have a harder time with 5001 elements than 1 element, so you’ll usually find that even if you were using plain() in both of those loops, it would take much longer the second time through.
If you run the tests separately, such that they WON’T interfere with each other, you’ll find that the results are about the same timing – memoization is a useful technique when you’re trying to only perform an intensive computation once instead of over and over, but the intensive part of plain() is inserting things into DOM structures, not a javascript lookup two objects deep. You’re not actually memoizing the hard part of the function, since for that particular function it wouldn’t make any sense to do so.