Writing Fast, Memory-Efficient JavaScript
coding.smashingmagazine.com
coding.smashingmagazine.com
When discussing the efficiency of a language, especially an interpreted language, one must always take into account the peculiarities of the used VM. And be sure that today's optimisations may be "pessimizations" in the future (see the many Linux optimisations that are being removed in the last years).
I suppose what you're really getting at is that in JS we are subject to the whims of BOTH the compiler and the VM on the target browser?
Also of note -- with C you make your product, compile it, ship it and largely forget about it. Its rare that PC games get slower, even if compilers change, because you don't keep recompiling it. However, if you make a JS game, that thing is interpreted from scratch every time its loaded. So if I make a JS game and ship it, the performance characteristics have a higher chance of changing in unexpected ways on me long after I've moved on.
(Note: This is simply a response to this particular aspect of performance tuning JS, I am obviously not getting into the benefits of interpretation which may very well outweigh these costs.)
No, because the core architecture is very stable and optimizes for existing programs, which uses the existing quirks of the previous architecture.
Not so for JS VMs.
...
This is horrible advice. There are plenty of things you want to delete, like references to elements when you don't need them anymore. A quick search of the Closure Library, jQuery, Backbone, Knockout, Angular.js, and ember.js found many uses of delete. Burn this article in a fire.
As for the supposed performance difference, let's see a jsperf on that.
Edit found one:
http://jsperf.com/delete-vs-undefined-vs-null/6
Delete is a little slower, certainly not enough to warrant the 'never' emphasis.
https://gist.github.com/4018282
Edit: I found a jsperf: http://jsperf.com/delete-vs-undefined-vs-null/6
Delete is a little slower, but setting null can be too, and setting undefined is the fastest for me in stable chrome.
JS engines will zero-in on these 'hot' objects and attempt to optimize access to it, a task which will be helped if object doesn't change in structure over its life-time. 'delete' will trigger such a structure change.
By structure in context of JS, one should think inferrable structure like always setting .a to a Number then .b to a String after instantiating an object.
The author mentions that programmers use delete for dereferencing. What?? That is completely opposite from what 'delete' means and should never be done, ever. Use 'delete' to remove keys from a map, not as a stupid GC hack. Also, 'null != undefined'. They have different meanings. null will show up in a for .. in loop, whereas a 'deleted' member is actually gone.
99% of performance problems are due to wrong code, not inefficient VMs. Write better code and you'll get faster programs. For those problems in the 1%, profile and fix.
That said, this (and many others) is probably not a concern for most (even most JS heavy) sites, since most simply don't compute enough to impact the page as much as, say, reducing reflows.
"Burn this article in a fire" :)
Looking back through my article I agree that stating delete should outright never be used didn't make sense. It's of course used in numerous JavaScript libraries and has a purpose in the language. I've updated the text to reflect my suggestion that it should be instead, avoided where possible. This advice stands as it's more difficult for V8 to optimize objects you're changing the structure of.
For others commenting on this thread, I've also taken account of some of your suggestions and tried to update the article to be as accurate as possible. Thanks for the input!
To "delete" is appropriate for hash-like structures, i.e., key-value maps. The runtime can't optimize these anyway; they will always be "generic slow objects". Plus, delete is the only way to remove the key, otherwise your hash will only grow in size, and you'd store a lot of "null" values for no reason that you'd have to explicitly filter.
Not sure I'll write it anymore though, this seems to have most of what I was going to say!
EDIT: After reading the article in more details, there are a few things I think it misses. My focus is more on games though. I still might write another article.
// Uses more memory:
Foo.prototype.someFunction = function () {
;[2, 5, 9].forEach(function (element, index, array) {
console.log("a[" + index + "] = " + element)
})
}
The function will be created every time the outer forEach loop is called. // Uses less memory:
Foo.prototype.logArrayElements = function (element, index, array) {
console.log("a[" + index + "] = " + element)
}
Foo.prototype.someFunction = function () {
;[2, 5, 9].forEach(this.logArrayElements)
}
Save your created functions for later to save memory.Where you have to be careful is if you have a function that's being called repeatedly and it contains a function instantiation -- that function will be reallocated each time.
[1,2,3].forEach(function(x) {
return (function(a, b) { return a * b })(x, 2)
})
Will repeatedly allocate that inner multiplication function, vs: mul = function(a, b) { return a * b }
;[1,2,3].forEach(function(x) {
return mul(x, 2)
})
Will only allocate that multiplication function once. ;[1,2,3].forEach(function(x) {
If this line is executed more than once, the nested function will be created again and again, wasting memory. However, some people may see my advice here as a micro-optimization. Thus, don't make your code ugly until you identify the real-world bottlenecks. I have updated my code in the grand-parent comment to explain myself a little more clearly (maybe)...