8 ms·
I think in most cases where you'd worry about JS array performance you should use actual numeric arrays [0] rather than the kitchen sink Array(). Also, I think
by throwaway_yy2Di 12y ago
I think in most cases where you'd worry about JS array performance you should use actual numeric arrays [0] rather than the kitchen sink Array(). Also, I think those function abstractions have a pretty significant overhead?
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays https://developer.mozilla.org/en-US/docs/Web/JavaScript/Type...
(edit): Yeah, the abstraction overhead is ridiculous. Here's the forEach() benchmark again, compared to an explicit for loop (no function calls):
// new benchmark in bench/for-each.js
exports['explicit iteration'] = function() {
acc = 0;
for (var j=0; j<input.length; ++j) {
acc += input[j];
}
}
Native .forEach() vs fast.forEach() vs explicit iteration
✓ Array::forEach() x 2,101,860 ops/sec ±1.50% (79 runs sampled)
✓ fast.forEach() x 5,433,935 ops/sec ±1.12% (90 runs sampled)
✓ explicit iteration x 28,714,606 ops/sec ±1.44% (87 runs sampled)
Winner is: explicit iteration (1266.15% faster)
(I ran this on Node "v0.11.14-pre", fresh from github).
- thegeomaster 12y agoI used this in a Firefox OS app, inside an implementation of Dijkstra's algorithm and an accompanying binary heap, and while I haven't run any rigorous benchmarks, I can say the runtime felt way better on my test phone when I rewrote the algorithm to use the typed arrays. This is very often overlooked but extremely useful for implementations of fast algorithms in JavaScript that should scale to a lot of input data.
- deleted 12y ago[deleted]
- phpnode 12y agoregarding your edit, you're exactly right, of course a for loop will be faster. Sometimes you really do need a function call though, in which case fast forEach and map implementations become more useful. The next step for fast.js are some sweet.js macros which will make writing for loops a bit nicer, because it's pretty painful to write this every time you want to iterate over an object: var keys = Object.keys(obj), length = keys.length, key, i; for (i = 0; i < length; i++) { key = keys[i]; // ... } I'd rather write: every key of obj { // ... } and have that expanded at compile time. Additionally there are some cases where you must use inline for loops (such as when slicing arguments objects, see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments https://github.com/petkaantonov/bluebird/wiki/Optimization-k...) and a function call is not possible. These can also be addressed with sweet.js macros.
- throwaway_yy2Di 12y agoTo be fair, it's not obvious if you're not a JS expert: coming from some other language, you could naively assume that function call gets inlined, with no overhead.
- k__ 12y agoA few months ago, I tried some image processing with JS and the canvas object (big Arrays). They have a structure like image[pixel].color What I found was, always traversing the object structure was much slower than putting every pixel color as an argument in a function, that gets called every iteration. So I had the impression, reasonable simple function, like a greyscale filter, get inlined by engines like V8.
- warfangle 12y agoYou probably would have been better off with typed arrays and fragment shaders, if you were going for performance.
- k__ 12y agoAren't the arrays produced by a canvas object typed?
- warfangle 12y agoYep, but they only become performant when you treat them as such instead of doing naive e.g. multiplication. See: https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/ https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipu...
- bzbarsky 12y agoLike any other compiler, function calls sometimes get inlined. And sometimes not. Depending on compiler heuristics of various sorts.
- 12y ago
- netghost 12y agoOne other micro optimization for you. Assuming the length of the array does not change in the operation, this is usually faster: for (var j=0, len=input.length; j < len; ++j) { This prevents rechecking the array length on every iteration.
- throwaway_yy2Di 12y agoI actually didn't get any speedup with that one -- looks like V8 can optimize that already. But you're right, that's an important one on some browsers. You can squeeze out another factor of 2 with typed arrays: var input_typed = new Uint32Array(input) exports['numeric typed array'] = function() { var acc = 0; for (var j=0; j<input_typed.length; ++j) { acc += input_typed[j]; } } ✓ Array::forEach() x 1,999,244 ops/sec ±2.93% (84 runs sampled) ✓ fast.forEach() x 5,161,137 ops/sec ±2.05% (85 runs sampled) ✓ explicit iteration x 27,851,200 ops/sec ±1.32% (86 runs sampled) ✓ explicit iteration w/precomputed array limit x 28,567,527 ops/sec ±1.33% (86 runs sampled) ✓ numeric typed array x 42,951,837 ops/sec ±0.97% (88 runs sampled) Winner is: numeric typed array (2048.40% faster) And probably more still if you can figure out the asm.js incantation that makes everything statically typed.
- WickyNilliams 12y agoThe optimisation mentioned by the grandparent is specific to looping overso-called "live" collections of the DOM. NodeList [0] is sometimes a live collection, and is the return type of querySelectorAll, so it's likely you've dealt with this type of collection. The reason it incurs an overhead is because the DOM is traversed every single time the property is read, to ensure nothing has changed. You can see why caching the length is a reasonable optimisation, as you're unlikely to be modifying the collection while looping. [0] https://developer.mozilla.org/en/docs/Web/API/NodeList https://developer.mozilla.org/en/docs/Web/API/NodeList
- BrandonLive 12y agoExactly. Although, I am curious if there's a reason the JS engine (possibly working with the DOM implementation) can't optimize that to one look-up, if the JS in the loop doesn't change that part of the DOM or call anything that forces it to yield. I suspect a lot of the optimization opportunity in browsers today is less about JS or DOM in isolation but more about ways they could work together to improve situations like this one. (Note: I understand this one is solvable by a proficient/attentive developer, but not all developers are like that, and not all such DOM/JS transition problems are as easily solvable from your JS code)