有没有可能以某种方式调用异步函数(例如计时器/ ajax调用),基本上是常见的异步任务,并在等待其结束时同步等待,而不会导致100%CPU使用率和阻塞浏览器?
不行。您无法在JavaScript中“同步等待”异步结果。由于它的单线程和事件驱动设计,它不会以这种方式工作。
由于大多数关于此问题的讨论/评论都是概念性的,因此我想提供一个关于如何使用适当的异步设计实际解决特定问题的答案。
JavaScript不提供在某些耗时活动完成时休眠的能力。因此,您无法将您的
updateCSS()
函数设计为具有纯同步接口。相反,您需要在JavaScript中使用异步工具来设计一个界面,该界面适用于资源被缓存和必须通过网络获取资源的情况。
通常的设计方法是设计一个异步接口,如果资源恰好被缓存,则仍通过异步接口提供它。然后,您有一个调用者可以使用的接口,该接口始终适用于资源是否被缓存。它要求调用者使用异步接口。
实际上,你可以像这样设计
getCachedResource()
:
function getCachedResource(url) {
if (cached) {
return Promise.resolve(cached);
} else {
return doAjax(...);
}
}
getCachedResource()
方法总是返回一个 Promise,无论值是否已被缓存。因此,调用者始终会像这样使用 promise 接口:
getCachedResource(...).then(function(result) {
});
如果结果恰好被缓存,
.then()
处理程序将立即被调用(在下一个时刻)。如果结果是通过网络检索的,则一旦结果可用,
.then()
处理程序将被调用。调用者不需要担心资源从哪里或以何种方式检索-他们有一个接口来获取它。
在
updateCSS()
函数中,您将不得不为使用
getCachedResource()
中的异步接口进行设计。因为您当前的设计在
css.replace()
中使用同步回调,所以您必须稍微重新考虑一下将异步检索适合其中。以下是如何执行此操作的一种方法。
function updateCSS(url) {
return getCachedResource(url).then(function(css) {
var urls = [];
css.replace(/regexp/gm, function(curUrl) {
urls.push(curUrl);
});
return Promise.all(urls.map(getCachedResource)).then(function(resources) {
var index = 0;
css = css.replace(/regexp/gm, function(curUrl) {
return resources[index++];
});
return css;
})
});
}
这里的方案是运行一个虚拟的
.replace()
,它不保留结果以生成您需要加载的URL列表。根据您的正则表达式,这也可以使用
.match()
或
.exec()
来完成。然后,一旦您获得了要获取的URL列表,请获取它们。当您拥有所有这些URL时,然后您可以真正运行
.replace()
,因为您有可用于在同步
.replace()
回调中使用的资源。
然后可以像这样使用它:
updateCss(someCSSURL).then(function(css) {
}).catch(function(err) {
});
async/await
,使其实用化时,答案将会是“是”。但是,有点。 - Pointy