为什么可以将`async`和`await`关键字分配给?

VLA*_*LAZ 5 javascript ecmascript-6

我注意到async关键字可以被分配任何值,甚至可以用作普通变量:

let async = "world";

console.log(async)
console.log("Hello " + async)
Run Code Online (Sandbox Code Playgroud)

但是,即使这样,它仍然可以像以前一样运行:

let async = "world";

async function foo(input) {
  return input;
}

let barPromise = foo("bar");

console.log("bar promise is:", typeof barPromise);

console.log("bar promise also has a .then:", typeof barPromise.then === "function");

barPromise
  .then(output => console.log("bar promise returns:", output));

console.log("async is still assigned:", async);

foo("Hello ")
  .then(output => console.log(output + async));
Run Code Online (Sandbox Code Playgroud)

甚至await在做同样的事情:

let await = "world";

console.log("await is:", await)

async function foo(input) {
  return input;
}

async function bar(input) {
  console.log("before");
  
  let output = await foo(input);
  console.log(output);
  
  console.log("after");
}

bar("hello")
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?为什么关键字可用作变量?

VLA*_*LAZ 9

答案最初是令人困惑的,但之后会有意义

  • 没有async关键字。有一个async function构造(MDN)链接至规范。因此,async只有在后跟函数时才具有特殊含义-作为表达式(传统函数和箭头函数)或声明。因此,称为的变量async是有效的,因为后跟的变量在function语法上无效。与语义没有冲突:

let foo;

//function declaration
foo function bar() {}; //SyntaxError
Run Code Online (Sandbox Code Playgroud)

let foo;

//function expression
let bar = foo function() {}; //SyntaxError
Run Code Online (Sandbox Code Playgroud)

  • 至于await,它实际上是一个运算符,而不是关键字,并且它是await表达式(MDN)的一部分链接到specs。语义要求await后面必须是一元表达式,并且必须在async函数内部-某些语法仍然无法与其他变量有效。

我没有任何消息来源,但是有理由得出这样的结论是为了保持向后兼容性。如果async在ES5中有用作变量的代码,稍后它将突然中断。通过async仅在其他情况下使您得到SyntaxError才有效,这确保了旧代码和新代码可以共存。相同await

有趣的是,的语义await实际上导致了最初又很奇怪的行为-您不能将其用作async函数内的变量。要么声明它:

async function foo() {
 let await = "world"; //SyntaxError - not a valid identifier here
}
Run Code Online (Sandbox Code Playgroud)

也不访问它:

let await = "world"; //valid identifier

async function foo() {
  console.log(await); //SyntaxError - it is not followed by an expression
}
Run Code Online (Sandbox Code Playgroud)

最初也令人困惑,但是,对于向后兼容是有意义的。即使将ES6之前的代码用作await变量,也不会在async函数中使用它,因为那些不存在。因此,旧代码有效,并且仍然没有冲突。