Javascript 使用;等待“;内部非异步函数
我有一个异步函数,它在代码中的某个地方按setInterval运行。此函数定期更新一些缓存 我还有一个不同的同步函数,它需要检索值——最好是从缓存中检索,但是如果是缓存未命中,则从数据源检索 (我意识到以同步方式进行IO操作是不明智的,但假设在这种情况下需要这样做) 我的问题是,我希望同步函数能够等待来自异步函数的值,但不可能在非Javascript 使用;等待“;内部非异步函数,javascript,asynchronous,async-await,Javascript,Asynchronous,Async Await,我有一个异步函数,它在代码中的某个地方按setInterval运行。此函数定期更新一些缓存 我还有一个不同的同步函数,它需要检索值——最好是从缓存中检索,但是如果是缓存未命中,则从数据源检索 (我意识到以同步方式进行IO操作是不明智的,但假设在这种情况下需要这样做) 我的问题是,我希望同步函数能够等待来自异步函数的值,但不可能在非async函数中使用wait关键字: function syncFunc(key) { if (!(key in cache)) { await
async
函数中使用wait
关键字:
function syncFunc(key) {
if (!(key in cache)) {
await updateCacheForKey([key]);
}
}
async function updateCacheForKey(keys) {
// updates cache for given keys
...
}
现在,通过将updateCacheForKey
中的逻辑提取到一个新的同步函数中,并从两个现有函数调用这个新函数,可以很容易地避免这种情况
我的问题是为什么一开始就绝对阻止这个用例?我唯一的猜测是它与“傻瓜证明”有关,因为在大多数情况下,等待同步函数的异步函数是错误的。但我认为它有时有其有效的用例,这是错误的吗
(我认为在C#中也可以通过使用Task.Wait
,尽管我可能会把这里的事情弄糊涂)
我的问题是我希望同步函数能够等待来自异步函数的值
他们不能,因为:
async
关键字可以应用于函数,但函数调用在JavaScript中始终是同步的。异步函数实际上并不存在。我们有同步函数,可以设置环境稍后将调用的回调(通过对作业排队),如果合适的话
让我们假设updateCacheForKey
看起来像这样:
async function updateCacheForKey(key) {
const value = await fetch(/*...*/);
cache[key] = value;
return value;
}
在封面下,它真正在做的是:
function updateCacheForKey(key) {
return fetch(/*...*/).then(result => {
const value = result;
cache[key] = value;
return value;
});
}
它要求浏览器开始提取数据的过程,并向其注册回调(通过然后
),以便浏览器在数据返回时调用,然后退出,从然后
返回承诺。数据尚未提取,但updateCacheForKey
已完成。它回来了。它的工作是同步进行的
稍后,当获取完成时,浏览器将作业排队以调用该承诺回调;当从队列中提取该作业时,将调用回调,其返回值用于解析承诺,然后返回
我的问题是为什么一开始就绝对阻止这个用例
让我们看看那会是什么样子:
线程拾取一个作业,该作业涉及调用syncFunc
,调用updateCacheForKey
updateCacheForKey
要求浏览器获取资源并返回其承诺。通过这种非异步wait
的魔力,我们同步地等待承诺得到解决,从而拖延了工作
在某个时刻,浏览器的网络代码完成了对资源的检索,并将一个作业排队,以调用我们在updateCacheForKey
中注册的承诺回调
再也不会发生任何事情了。:-)
…因为作业已运行到完成语义,线程在完成前一个作业之前不允许拾取下一个作业。线程不允许在中间挂起名为>代码> SycFunc < /C>的作业,这样它就可以处理将要解决的任务。
这似乎是武断的,但再次强调,其原因是它使编写正确的代码变得非常容易,并说明代码正在做什么
但这确实意味着“同步”函数不能等待“异步”函数完成
上面有很多细节和类似的东西。如果你想深入了解它的本质,你可以深入研究它的规格。带上大量的食物和暖和的衣服,你会有一段时间的。:-)
- 及
您可以通过以下方式从非异步函数中调用异步函数:
如你的例子所示:
function syncFunc(key) {
if (!(key in cache)) {
(async () => await updateCacheForKey([key]))();
}
}
async function updateCacheForKey(keys) {
// updates cache for given keys
...
}
现在,通过将updateCacheForKey内部的逻辑提取到一个新的同步函数中,并从两个现有函数调用这个新函数,可以很容易地避免这种情况
完美地解释了JavaScript中异步函数的语义。但在我看来,上述段落值得更多讨论。根据updateCacheForKey
的功能,可能无法提取其逻辑i
function syncFunc(key) {
if (!(key in cache)) {
(async () => await updateCacheForKey([key]))();
}
}
async function updateCacheForKey(keys) {
// updates cache for given keys
...
}