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



考虑一下我在其中一个项目中注意到的以下奇怪行为:

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 的编译目标设置为es3es5时,arguments关键字阻止它在异步函数中使用是什么?

一些注意事项:

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

我的假设

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

延伸阅读: ES5.1 规范 § 10.6 参数对象

这是因为异步函数被转译为生成器的基本多填充实现;这个实现基本上交换了函数的主体,将其包装在另一个函数中,因此任何对arguments的使用都将永远不会访问 hello 的原始arguments,而是__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(参数)已经从 hello 的上下文转移到了__generator的上下文,这意味着它永远不会按照您的预期运行。如果您的目标是现代浏览器(非IE),则可以将编译目标设置为ES6+,在这种情况下,将删除此限制。

只需使用点差运算符

hello(...args: any[])

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

你是绝对正确的。

我想分享另一种观点,说明为什么这不起作用:

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

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

随着async关键字的引入,async函数无法完成。它们将被拆分为较小的任务(通过await)。

现在,如果您必须将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对象,但是您将不得不使用其他不受支持的较新的语言功能(getter/setter,代理)。老实说:你不应该使用arguments因此翻译它不值得麻烦。

相关内容

  • 没有找到相关文章

最新更新