Not sure which particular project this issue belongs to, but I guess let's track it here for now.
Currently microbundle results in extra bytes in code using for-of (found this as part of dlv experiments).
Example:
export default function dlv(arr, x, sum) {
sum = 0;
for (x of arr) {
sum += x;
}
return sum;
}
Currently results in:
export default function(r,t,e){e=0;for(var n=0,f=r;n<f.length;n+=1)e+=f[n];return e}
This is suboptimal for several reasons:
for-of is done over an existing variable, the result currently introduces yet another one - f - just to store the array again.t is completely unused in the result, when it could be reused for other purposes (e.g. the counter).n+=1 should be replaced with just f++.An optimal output would instead look like:
export default function(r,t,e){for(t=0,e=0;t<r.length;t++)e+=r[t];return e}
This is a Bubl茅-ism. Should be solved by #362 or one of the other bubl茅-->babel PR's.
I find it interesting though that Terser wouldn't have compressed the output to look like your final version. Perhaps it's avoiding assigning to arguments because it doesn't know the resulting code will be run in strict mode?
Perhaps it's avoiding assigning to arguments because it doesn't know the resulting code will be run in strict mode?
Maybe... What I find even more surprising though is the +=1 bit - that one should certainly be equivalent to ++ in any context and is sort of obvious for a minifier.
What I find even more surprising though is the +=1 bit - that one should certainly be equivalent to ++ in any context and is sort of obvious for a minifier.
Many have proposed it. Nothing is obvious in javascript.
$ echo 'for (var i="0", x=0; i<9; i+=1, x+=1) if (!x) x+=""; console.log(x)' | node
011
$ echo 'for (var i="0", x=0; i<9; ++i, x+=1) if (!x) x+=""; console.log(x)' | node
0111111111
$ echo 'for (var i="0", x=0; i<9; i+=1, ++x) if (!x) x+=""; console.log(x)' | node
2
$ echo 'for (var i="0", x=0; i<9; ++i, ++x) if (!x) x+=""; console.log(x)' | node
9
The minifier would need to implement control flow and type analysis to do that correctly.
FYI: asked this question on Twitter: https://twitter.com/marvinhagemeist/status/1133074844906606594
@bmeurer @mathiasbynens On another topic, are there any JS engine performance implications of repurposing function parameters as local scratch variables instead of explicitly declaring local vars? The function parameters x and sum in the top post are an example of this.
I recall that Google Closure Compiler used to perform this sort of transform to reduce code size. Perhaps it still does.
If you declare additional parameters that are not passed at the call site, then you incur a small call overhead, since the engine has to (dynamically) pad the parameters with undefined. Whether or not that's worth the code size savings is up to you to decide.
If you declare additional parameters that are not passed at the call site, then you incur a small call overhead,
More info: https://v8.dev/blog/v8-release-74#faster-calls-with-arguments-mismatch
The minifier would need to implement control flow
@kzc Doesn't the minifier already implement basic control flow checks for other optimisations? Although, in this particular case, I suppose it's easier to fix the transpiler side to produce ++ in the first place.
Doesn't the minifier already implement basic control flow checks for other optimisations?
The uglify derived minifiers presently implement a varied set of AST heuristics, often involving tree scanning, for specific tasks that collectively give the illusion of complete control flow analysis. There is no SSA or anything like that that'd be required for comprehensive type analysis. However, you can get a long way with specific directed optimizations. Take a look at the documentation for the compress options, or examine the code for more details.
At the end of the day, some optimizations are not worth doing if their occurrences in real life code are infrequent, or if minification payoff is negligible (particularly post gzip), or if the runtime analysis cost is prohibitively expensive. You also have to weigh the implementation complexity and the resultant maintenance issues for an open source project run by a couple of people in their spare time.
Most helpful comment
Many have proposed it. Nothing is obvious in javascript.
The minifier would need to implement control flow and type analysis to do that correctly.