TypeScript的省略号会影响性能吗?

5

Typescript的省略符会生成JavaScript代码,该代码会在函数开头将arguments转换为一个数组。

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

变成:

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

在考虑项目的性能时,我想知道这个结构是否会影响常被调用的代码的性能问题?

会吗?

3个回答

7
回答这个问题最简单的方法是运行一些测试。 JsPerf 是一个非常棒的工具。我自己也很好奇,所以我在这里设置了一个测试,是的,它可能会导致显著的性能损失。这取决于您调用该函数的频率、它所执行的工作量以及参数列表可能变得多长。
尽管如此,我非常相信80/20法则,特别是在优化方面。大多数时间它并不重要,所以如果它使代码更美观,请放心使用。

根据我运行测试的浏览器不同,结果差异很大。IE和FireFox不能直接使用参数,而Chrome在这方面最快。这真的很有趣。 - Jeffery Grajkowski
这是针对“rest”参数而言的,不是数组参数。因此,如果您要向函数传递超过10个参数,那么我认为可能会有更大的问题。 - basarat

1
我同意Jeffrey的答案,但我认为有一个问题被忽略了。
你问是否使用rest参数会导致性能下降,但与什么相比呢?
例如,如果我有以下函数:
var addNums = function(...nums: number[]) {
    var result = 0;
    for (var i = 0; i < nums.length; i++) {
        result += nums[i];
    }
    return result;
};

我可以使用哪些替代方法?

如果我想避免剩余参数,我可能仍然会接受一个数组参数,因为我们不知道可能有多少个数字。在这两种情况下,运行时性能是相似的。因此,剩余参数只是调用代码的一种方便:

addNums(1,1,2,3);

Rather than

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

如果TypeScript具有其自身函数体的方法重载,您可以执行与C#框架类库中使用的相同技巧,即为一系列重载提供固定方法,并使用剩余参数来处理具有更多参数的情况。例如,您将拥有以下方法签名:
addNums(a: number, b: number)
addNums(a: number, b: number, c: number)
addNums(...nums: number[])

在一般情况下,将调用不使用循环的版本,但在边缘情况下会运行更低效的版本。
您可以尝试在TypeScript中实现此功能,但需要为所有重载提供一个兼容的单个方法体,然后检查参数,这不太可能更快(虽然您可以测量它)。
因此,除非您打算调用此方法一千次以上,否则它不太可能比其他选择更差。

0

我也很好奇,因为我的日志函数使用它们并且被频繁调用。

我进行了测试。

function toArray(obj, start)
{
  var arr=[];
  for (var i=start||0, j=0, len=obj.length; i<len; ++i)
      arr[j++]=obj[i];
  return arr;
}

function toArrayPush(obj, start)
{
  var arr=[];
  for (var i=start||0, len=obj.length; i<len; ++i)
      arr.push(obj[i]);
  return arr;
}

function testArgToArrayPush(level)
{
  var args=toArrayPush(arguments, 1);
}

function testArgToArray(level)
{
  var args=toArray(arguments, 1);
}

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

function testArgSlice(level)
{
  var args=Array.prototype.slice.call(arguments, 1);
}

在 node.js v0.10.18 上使用优秀的 benchmarkjs.com:
testArgToArrayPush x 4,505,312 ops/sec ±0.55% (64 runs sampled)
testArgToArray x 2,961,857 ops/sec ±2.37% (93 runs sampled)
testArgTypescript x 3,879,242 ops/sec ±1.15% (96 runs sampled)
testArgSlice x 1,060,084 ops/sec ±0.52% (95 runs sampled)
Fastest is testArgToArrayPush

这意味着

  • 对于大多数情况来说,Typescript版本已经足够好了
  • 如果你有热点问题,考虑使用toArrayPush()
  • 避免使用Array.prototype.slice()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接