为什么在JavaScript函数体内调用await需要异步?
必须在包含函数上使用async关键字才能在函数体内使用await。
async function fetchMovies() {
const response = await fetch('/movies');
console.log(response);
}
fetchMovies();
在AWAIT被用来对异步完成方框取()调用。从代码中可以看出,函数fetchMovies()甚至没有返回任何值。即使这样做了,它也会影响调用者使用返回值的方式,但是为什么它会影响从函数体调用另一个异步调用呢?
我的问题是为什么需要这样做?有什么好的解释吗?它是否与实际实现await的需要有关,并在旧的 JavaScript 版本中支持它?
我知道使用了iffi模式能够使用await但这是否会以任何方式更改iffi代码块后面的代码的语义?
(async () => {
const response = await fetch('/movies');
console.log(response);
})();
我也知道模块中支持顶级等待。
可能是我错过了一些非常明显的东西。
回答
async
关键字存在的三个原因:
-
在 2015 年之前的 ECMAScript 语言版本中,
await
不是关键字。标记函数async
提供了句法“救助”以指示函数主体内语言语法的重大变化。这是最重要的原因。如果没有
async
关键字,所有用 ECMAScript 5 或更早版本编写的程序如果使用await
关键字作为变量将不再工作(事实上,在某些情况下,这是有意在async
/await
标准化之前作为 polyfill 完成的),因为这会导致重大更改没有添加async
到规范中。因此,async
在语法上是必要的,以避免对语言进行破坏性更改。 -
它为解析器提供了一个方便的标记,避免了无限前瞻以确定函数是否异步。
这使得解析更高效,这对 ECMAScript 实现者和开发人员都很有吸引力,尽管仅凭这个原因并不能
async
严格要求语法。 -
async
还对函数执行自己的转换,无论await
关键字是否存在于主体中,都会进行转换。考虑以下两个函数:
function foo() { if (Math.random() < 0.5) { return 'return'; } else { throw 'throw'; } } async function bar() { if (Math.random() < 0.5) { return 'return'; } else { throw 'throw'; } }
async
执行以下转换function bar()
:function bar() { return new Promise((resolve, reject) => { try { resolve((/*async function bar*/() => { if (Math.random() < 0.5) { return 'return'; } else { throw 'throw'; } })()); } catch (reason) { reject(reason); } }); }
熟悉 Promise 的人会认识到我们可以简化上面的内容,因为 Promise 构造函数 executor 函数在同步抛出错误时将隐式拒绝:
function bar() { return new Promise((resolve) => { if (Math.random() < 0.5) { return resolve('return'); } else { throw 'throw'; } }); }
- Also, as I understand it, async/await as a syntax existed in C# a few years before it was in ES, and Python somewhere in-between. I wouldn't be surprised if that played an influence. Of course, that's begging the question a bit, as your reasons above surely apply to the predecessor languages as well.