TypeScript:异步函数中的arguments关键字

时间:2019-06-27 20:19:58

标签: javascript typescript async-await

考虑一下我在一个项目中发现的以下奇怪行为:

async function hello() {
  return arguments;
}

当TypeScript的编译目标设置为es3es5时,以上文件无法编译,并出现以下错误:

error TS2522: The 'arguments' object cannot be referenced in an async function or method in ES3 and ES5. Consider using a standard function or method.

2   return arguments;
           ~~~~~~~~~

但是,对于更高的编译目标(我已经测试过es2017esnext),没有错误。


当TypeScript的编译目标设置为argumentses3时,如何阻止es5关键字在异步函数中使用?

一些注意事项:

  • 在现代JavaScript中复制时,此函数不会引发异常
  • 只能在async个函数中复制此行为

我的假设

我怀疑因为Promise需要在es3es5中进行多填充,所以polyfill不支持arguments,因为它依赖于函数被调用者。

进一步阅读:ES5.1 Spec § 10.6 Arguments Object

3 个答案:

答案 0 :(得分:2)

这是因为Async函数被转换为生成器的基本polyfilled实现;此实现基本上会交换您的函数主体,以将其包装在另一个函数中,因此,arguments的任何使用都不会访问原始的arguments的hello,而是访问__generator

下面是一个示例,其中hello不带任何参数并生成以下内容,其中函数的主体包装在另一个函数中。

async function hello() {
    console.log(arguments);
} // becomes.....


function hello() {
    return __awaiter(this, arguments, void 0, function () {
        return __generator(this, function (_a) {
            console.log(arguments);
            return [2 /*return*/];
        });
    });
}
再次重申,console.log(arguments)已从hello上下文移至__generator上下文,这意味着它永远不会像您期望的那样运行。如果您针对的是现代浏览器(非IE),则可以将编译目标设置为ES6 +,在这种情况下,此限制将被消除。

答案 1 :(得分:1)

只需使用传播运算符

hello(...args: any[])

现在您有一个数组或传入的参数。

答案 2 :(得分:-1)

您绝对正确。

对于这种方法为什么行不通,我想分享另一种观点:

JavaScript具有基于任务的并发性,这意味着代码被分解为小的“块”(任务),并且一次执行其中一个。如果您将异步事务划分为多个任务,那么一个异步任务将启动异步操作,而异步操作完成后将处理结果。同时可以执行其他任务,从而允许并发。

现在,可能的最小执行块是(在async之前)一个函数:一个函数始终运行到完成,您不能将一个函数拆分为多个任务。

通过引入async关键字,有async个函数无法运行完成。它们将分解为较小的任务(通过await s)。

现在,如果您必须将async function转换为常规function,则会遇到一个问题:您无法拆分任务。因此,您需要多个函数来表示一个async function

   async function(arg) { await a(); await b(); }
   // becomes
   function(arg) { return a().then(function () { b(); }); }

现在可以看到它并不能完全转换:尽管arg是唯一的async函数的自变量,但只有外部函数具有那个arg。但是,通常这不是问题,无论您是在当前范围内还是在外部范围内访问arg都不会改变工作方式(除非您重新声明)。

但是,有一件事情被改变了,它构成了这个答案:arguments。因为我们有两个函数,所以我们确实有两个arguments对象。现在,您也可以模仿arguments对象,但随后您将不得不使用其他不受支持的较新语言功能(getters / setters,Proxies)。老实说:您不应该使用arguments,因此进行编译不值得麻烦。