为什么等待和异步有效的变量名?

Cer*_*nce 30 javascript specifications language-design async-await es2017

我尝试使用/不同的关键字和运算符时如何解释,发现以下语法完全合法:

// awaiting something that isn't a Promise is fine, it's just strange to do:
const foo = await /barbaz/
myFn()
Run Code Online (Sandbox Code Playgroud)

错误:

未捕获的ReferenceError:未定义等待

看起来它尝试将解析await变量名 ..?我期待

等待仅在异步功能中有效

或类似的东西

意外的令牌等待

令我恐惧的是,您甚至可以为其分配以下内容:

const await = 'Wait, this actually works?';
console.log(await);
Run Code Online (Sandbox Code Playgroud)

如若不是如此明显的错误原因语法错误,因为它确实有letfinallybreak,等?为什么允许这样做?第一个代码片段到底发生了什么?

Cer*_*nce 59

保留的关键字不能用作标识符(变量名)。与大多数其他特殊的Javascript的话(像那些在这个问题列出letfinally...),await不是一个保留关键字,所以使用它作为一个变量名不抛出一个SyntaxError。当新语法出现时,为什么不将其变成保留关键字?

向后兼容

早在2011年,当ES5还是一个相对较新的事物时,使用await(和async)作为变量名的代码是完全有效的,因此您可能在几个站点上看到了类似的东西:

function timeout(ms) {
  var await = $.Deferred();
  setTimeout(await.resolve, ms);
  return await.promise();
};
Run Code Online (Sandbox Code Playgroud)

该变量名的选择可能看起来很奇怪,但没有任何问题await并且async从来没有保留关键字-如果将ES2017规范的编写者设置await为保留关键字,并且浏览器实现了该更改,则在较新的浏览器上访问那些较旧网站的人将无法使用这些网站;他们可能会被打破。

因此,也许如果将它们变成保留关键字,那么一些选择了特殊变量名称的站点将无法正常工作-为什么这些站点的存在会永久性地影响ECMAscript的未来发展并导致代码混乱,如问题所在?

因为浏览器将拒绝实施破坏现有站点的功能。如果用户发现某个网站不能在一个浏览器上运行,而是在另一个浏览器上工作,则将激励他们切换浏览器-第一个浏览器的制造商不希望这样做,因为这将意味着它们的市场份额较小,即使它的功能使语言更加一致和易于理解。另外,规范的编辑者不希望添加一些永远不会实现的内容(或只会偶尔实现),因为那样的话,规范将失去其作为标准的地位-与其主要目标相反。

你可以看到这些相互作用在用行动Array.prototype.flattenArray.prototype.contains-当浏览器开始出货他们,发现他们分手,由于名称冲突的几个现有的网站,所以浏览器实施的退了出去,和规格不得不进行调整(方法被重命名为.flat.includes)。


实际上有其中的情况await不能被用作标识符,这是ES6模块内:

function timeout(ms) {
  var await = $.Deferred();
  setTimeout(await.resolve, ms);
  return await.promise();
};
Run Code Online (Sandbox Code Playgroud)

这是因为在确定ES6(ES2015)模块的同时,async/ await已经面世(/ 提案的初始提交asyncawait可以在2014年初看到),因此在设计模块时,await可以在准备模块时将其作为保留关键字。面向未来,而不会破坏任何现有站点。


关于问题的第一个片段:

<script type="module">
  const await = 'Does it work?';
</script>
Run Code Online (Sandbox Code Playgroud)

这在语法上是有效的,因为它awaitasync函数之外的有效变量名,并且解释器认为您正在尝试除法,而不是使用正则表达式:

const foo = await / barbaz / myFn()
Run Code Online (Sandbox Code Playgroud)

不依赖自动分号插入会更早地发现问题,因为最后一个/不能解释为除法:

const foo = await /barbaz/
myFn()
Run Code Online (Sandbox Code Playgroud)

这种精确的有些暧昧的情况实际上是专门在长大TC39会议async/ await

杨:您担心什么?

WH:代码序列中以await /开头的歧义,然后以不同的方式进行解释(由于await-as-identifier与await-as-operator的区别,这会在覆盖语法vs.之间引起翻转(在除法和开始一个正则表达式之间)。真正的语法。这是一个潜在的错误农场。

  • 今天和自己说话。.不,只是开个好玩笑。在您做出回应之前,我最初的直觉是兼容性。我认为这也是为什么不保留`of`的原因,就像在`for of`中一样,尽管即使在模块模式下这仍然有效。 (2认同)
  • 您认为向后兼容是正确的。这就是为什么我们还必须在函数声明站点添加“ async”关键字以将上下文从“ await is a identifier”更改为“ await is a keyword”的原因。出于完全相同的原因,我们有`function *`和`yield`,它也是生成器外部的有效标识符名称。 (2认同)