3 ms·
Any articles/resources on writing high-performance JS that you would recommend? I don't use JS for work, but just for random fun stuff. So just curious to learn
by truncate 8y ago
Any articles/resources on writing high-performance JS that you would recommend? I don't use JS for work, but just for random fun stuff. So just curious to learn more about it.
- snek 8y agoJust write idiomatic code, it's what all the major engines try to optimize for.
- dahart 8y agoCheck out gl-matrix.js, that’s one designed for being fast. It’s a simple math library, but the main way it achieves fast is by not allocating memory. After having worked on JS for some large web apps that need good graphics performance, the two rules of thumb in my head for making JS fast are: 1- avoid dynamic memory allocation, and 2- avoid using the functional primitives like map. The first one is more or less true in all languages, memory allocation always costs a lot, and if you can pre-allocate memory and/or re-use memory along the way, the code will run faster. This means paying attention to what things in JavaScript will allocate memory under the hood, use of dicts, use of 3rd party library and framework functions, etc. The second one is a bummer; I love using the functional primitives. But map is slower than a for loop, all else being equal. It has gotten relatively faster over time. I mostly use functional everywhere, and only resort to for loops in performance critical code.
- javitury 8y ago> 2- avoid using the functional primitives like map I understand that map requires creating a new array, and that is already included in point 1. What overhead are functional primitives subject to apart from memory allocation? e.g. forEach
- dahart 8y agoUsing continuations. The function call itself and the local scope wrapped up into it can be varying degrees of expensive. When little state, because it’s inline or nearby for example, it might be optimized down to near what a for loop does. But if there’s a function call at all once it’s executed, that alone is slower than the for loop. Remember it’s a function call per element. If the function is further away with more scope, it can be more expensive both memory wise and time wise. BTW, it's easy to test the basic primitives. I use Chrome snippets. test = (name, fn) => { const timeLimitMs = 1000 let start = Date.now(), count = 0 while (Date.now() - start < timeLimitMs) { fn(); count++ } console.log(name, count) } var N = 1000000 let a = new Array(N) test('for loop', _=> { for (var i = 0; i < N; i++) a[i] = i }) test('map', _=> { a = a.map((x,i) => i) }) test('forEach', _=> { a.forEach((v,i,a) => a[i] = i) }) for loop 941 map 37 forEach 69 This is on my Mac in Chrome. So forEach is faster than map, but for loop is more than 10x faster than forEach. That's for loops with trivial work, of course. If the inside of the loop is expensive, the loop/map ratio will be lower.
- nicoburns 8y agoIf I modify that code to pre-initialise an array with the values 0 to N - 1, and then copy the value from that array to a new array (rather than using the loop index), then both map and forEach are faster than the for loop for me.
- dahart 8y agoThat sounds fairly surprising, considering map has to allocate, and allocate is very expensive, but please share your code & I’ll try it. Like so? const N = 1000000 let a = new Array(N), b = new Array(N) for (let i = 0; i < N; i++) a[i] = i test('copy loop', _=> { for (var i = 0; i < N; i++) b[i] = a[i] }) test('copy map', _=> { b = a.map((x,i) => a[i]) }) test('copy forEach', _=> { a.forEach((v,i,a) => b[i] = a[i]) }) I get: copy loop 973, copy map 38, copy forEach 49. Same as before, but this time I tried Chrome in Windows. Are you using a different browser? I know that sometimes other browsers have very different results. In any case, it's somewhat irrelevant if there are cases that optimize and cases that don't. When idiomatic functional code is sometimes up to 30x slower than a for loop, it can't be used in perf critical sections. Even if it's only Chrome and only certain cases. The forEach perf needs to be always reliably performant before I can use it without worry.
- javitury 8y agoThank you for the explanation