必须在包含函数上使用async关键字,才能在函数体内使用等待。
async function fetchMovies() {
const response = await fetch('/movies');
console.log(response);
}
fetchMovies();
wait用于在异步fetch()调用完成时进行阻塞。从代码中可以看出,函数fetchMovies()甚至没有返回任何值。即使是这样,它也会影响调用者使用返回值的方式,但为什么这对函数体对另一个异步调用的调用很重要呢?
我的问题是为什么需要这样做?对此有什么好的解释吗?它是否与实际实现wait并在旧的JavaScript版本中支持它的需求有关?
我知道使用iffi模式可以使用等待,但这会以任何方式改变ifi 我还知道模块中支持顶级等待。 可能是我错过了一些非常明显的东西。(async () => {
const response = await fetch('/movies');
console.log(response);
})();
async
关键字存在有三个原因:
-
在2015年之前的ECMAScript语言版本中,
await
不是关键字。标记函数CCD_;救助;以指示函数体内语言语法的突破性变化。这是最重要的原因。如果没有
async
关键字,如果使用await
关键字作为变量(事实上,在async
/await
标准化之前,在某些情况下,这是故意作为polyfill进行的),那么用ECMAScript 5或更早版本编写的所有程序都将不再工作,因为如果不在规范中添加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'; } }); }
这里有两个问题。为什么需要async关键字来指示异步上下文,为什么需要asynccontext来使用await?
如果我们不使用async关键字来指示异步上下文,那么我们将存在向后兼容性问题。在异步/等待更新之前;等待";是一个有效的变量名。因此,为了使它成为一个保留词,我们需要引入一个新的上下文,异步函数上下文。
第二个问题是,我们为什么要这样做?为什么我们要将异步函数与传统的同步代码区分开来?顾名思义,异步函数不会同时执行所有代码。当函数";等待";,它有效地停止了执行,代码的其余部分变成了正在等待的事情的事件处理程序。这允许运行其他代码。
浏览器javascript实现是单线程的。一次只能执行一件事,但事件队列允许函数轮流执行。考虑一下,如果您可以从同步函数等待,会发生什么。根据定义,同步代码不会放弃控制。因此,它正在等待的异步函数将永远不会有机会切换到您的单个执行线程,您将永远等待。因此,只有在已经处于异步上下文中的情况下,才能等待异步函数。
我想你的确切问题是:">处理返回值(null或其他值)取决于调用函数的使用者。他们";应该";即使在两者之间调用了另一个异步函数,也应该得到它。那么,为什么在进行其他异步调用之前等待很重要呢";
你看,这样的fetch()
调用是在数据库中在"0"的持续时间内完成的;启动";以及";关闭";连接。在这种情况下,几乎所有使用的方法都是异步的。因此,在执行fetchMovies();
时,线程可能会进一步移动,并在解析和返回获取之前执行connection.close();
。
具体情况如下:
await client.connect(); //connection establishment
// Your purposeful methods
async function fetchMovies() {
const response = await fetch('/movies');
console.log(response);
}
await fetchMovies();
// Closing connection to avoid attacks and maintain concurrency
await client.close();
在这种情况下,如果以异步方式调用任何方法,则数据库连接的整个会话都将被浪费,并且我们的函数将返回undefined
或抛出错误"em";无法使用已结束的会话">
因此,我们需要";等待";对于";挂起";承诺达成";实现了";或";被拒绝";状态,然后再执行进一步的调用。
您可以更多地参考本文:使用Promises,异步/等待MongoDB只是为了便于理解。
我认为这是为了明确该函数包含异步代码。让我们使用另一个返回某些内容的示例:
async function canUseGeolocation() {
const result = await navigator.permissions.query({name: 'geolocation'});
return result.state;
}
async
关键字告诉javascript引擎,函数应该返回一个promise,函数中的任何返回语句都应该解析该promise。如果我们修改它以缓存值,这样我们就不会总是调用wait,会发生什么?
function canUseGeolocation() {
if (cachedPermissionState) return cachedPermissionState;
const result = await navigator.permissions.query({name: 'geolocation'});
cachedPermissionState = result.state;
return result.state;
}
javascript应该如何知道函数应该返回promise?因为它包含一个await
?如果您稍后更改函数,使cachedPermissionState
设置在其他位置,而此函数仅返回该值,从而删除await
,该怎么办?第一个return语句应该返回promise还是返回值?这将改变函数的整个执行方式以及return cachedPermissionState;
返回的内容。通过使用async
,我们可以知道它确实返回了一个promise,return语句解析了这个promise,而无需扫描函数中的await
语句来确定它是否应该被视为async
。