考虑一下我在一个项目中发现的以下奇怪行为:
async function hello() {
return arguments;
}
当TypeScript的编译目标设置为es3
或es5
时,以上文件无法编译,并出现以下错误:
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;
~~~~~~~~~
但是,对于更高的编译目标(我已经测试过es2017
和esnext
),没有错误。
当TypeScript的编译目标设置为arguments
或es3
时,如何阻止es5
关键字在异步函数中使用?
一些注意事项:
async
个函数中复制此行为我的假设
我怀疑因为Promise
需要在es3
和es5
中进行多填充,所以polyfill不支持arguments
,因为它依赖于函数被调用者。
答案 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
,因此进行编译不值得麻烦。