Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a typescript ellipsis a performance concern?

Typescript ellipsis generates JavaScript which constructs an array out of arguments at the beginning of the function.

function blah(...args: any[]){
}

becomes:

function blah() {
    var args = [];
    for (var _i = 0; _i < (arguments.length - 0); _i++) {
        args[_i] = arguments[_i + 0];
    }
}

Looking over my project with performance in mind, I'm wondering whether this construction is a performance concern for often called code?

Is it?

like image 602
noop Avatar asked Feb 16 '23 18:02

noop


2 Answers

The easiest way to answer that question is to run some tests. JsPerf is a pretty awesome tool for that. I was curious myself so I set up a test over here and yes, it could be a significant performance hit. How much depends on how often you call that function, the amount of work it does and how long the parameter list is likely to get.

All of that said I'm a big believer in the 80/20 rule, especially when it comes to optimization. Most of the time it won't matter, so if it makes the code more beautiful go ahead and use it.

like image 83
Jeffery Grajkowski Avatar answered Feb 19 '23 23:02

Jeffery Grajkowski


I agree with Jeffrey's answer but I think a point has been missed.

You ask whether a rest parameter causes a performance hit, but compared to what?

For example, if I had the following function:

var addNums = function(...nums: number[]) {
    var result = 0;
    for (var i = 0; i < nums.length; i++) {
        result += nums[i];
    }
    return result;
};

What alternatives can I use?

If I wanted to avoid the rest parameter, I would probably accept an array argument still given we don't know how many nums there may be. The runtime performance would be similar in these two scenarios. Therefore the rest parameter is just a convenience for the calling code:

addNums(1,1,2,3);

Rather than

addNums([1,1,2,3]);

If TypeScript had method overloads with their own function bodies, you could do the same trick that has been used in the C# framework class library, whereby you supply fixed methods for a series of overloads and use the rest parameter to handle cases with greater numbers of arguments - for example you would have method signatures such as:

addNums(a: number, b: number)
addNums(a: number, b: number, c: number)
addNums(...nums: number[])

So in your common cases, the non-looping version would be called, but in edge cases the less performant version would run.

You could try this in TypeScript, but you would need to provide a single compatible method body for all of the overloads and then check the arguments which is unlikely to be faster (although you could measure it).

So unless you are going to call this method a thousand times, it is unlikely to be worse than an alternative.

like image 20
Fenton Avatar answered Feb 19 '23 22:02

Fenton