async/await 会阻塞事件循环吗? [复制]
Posted
技术标签:
【中文标题】async/await 会阻塞事件循环吗? [复制]【英文标题】:Does async/await blocks event loop? [duplicate] 【发布时间】:2019-01-06 02:02:51 【问题描述】:我正在阅读 Node.js 指南中的 Don't Block the Event Loop。有一句话说:
您应该确保永远不会阻塞事件循环。换一种说法, 您的每个 javascript 回调都应该快速完成。这个 当然也适用于你的
await
,你的Promise.then
,等等。
我开始怀疑,如果我 await
ing 对数据库的一些 API 调用需要一些时间来解决,这是否意味着我已经用 await
调用阻止了事件循环?
在那之后,我开始测试一些自己编写的代码,但是在测试之后我仍然不清楚通过await
阻止是如何工作的。以下是一些测试代码:
假设我正在使用 express 进行测试。我明白为什么在这种情况下对 /test
路由进行 2 次 API 调用会阻塞事件循环。
function someHeavyWork()
// like calling pbkdf2 function
app.get('/test', (req, res) =>
someHeavyWork();
res.json(data);
);
但在这种情况下不会发生这种情况。
function fakeDBCall()
return new Promise((resolve, reject) =>
setTimeout(() =>
resolve(data);
, 5000)
)
app.get('/test', async (req, res) =>
const data = await fakeDbCall();
res.json(data);
)
这可能是因为我对 async/await
的情况下的阻塞如何工作缺乏了解。
【问题讨论】:
【参考方案1】:与看起来相反,await
不会阻止。这只是 语法糖 的承诺。没有任何东西被阻塞;允许代码同步可能看起来很阻塞,但这只是对承诺的糖分。例如,这可能看起来是同步的:
const response = await fetch(…);
const json = await response.json();
const foo = JSON.parse(json); // Using json here, even though my request was async!
但事实并非如此。一旦你去糖,你得到的只是承诺,它们是非阻塞的:
fetch(…)
.then(response => response.json())
.then(json =>
const foo = JSON.parse(json);
);
如果await
被阻塞,那绝对是灾难性的。 JavaScript 运行时通常是单线程的。这意味着只要您发出请求或其他异步操作(例如使用文件系统),用户交互和其他进程就会停止。在相关说明中,这与动态导入一起是 main argument against top level await
【讨论】:
了解为什么第二次调用没有阻塞事件循环。一个简单的问题,当 promise 解决时,then
的回调是否被事件循环推送到调用堆栈,如果没有,那么它是如何被推送到它的?
@MohammadAziz 在内部,await
执行PerformPromiseThen,基本上就是Promise#then
。在操作中,一个new Job is enqueued (with the callback)。一旦调用堆栈为空,这些作业就会执行(因此通过事件循环,一旦调用堆栈为空,就会将新作业推送到调用堆栈)。
另外,在第一个示例中,您有优势来操作 response
和 json
对象。我的意思是,迭代对象或获取其他信息。【参考方案2】:
异步函数返回一个promise,你传入请求和响应,我会改变 res.json(数据) 到 返回 res.json(数据)
当异步函数返回值时,promise 被解析,如果函数包含错误,promise 被拒绝,只是为了清洁返回 res.json(data) 将解析函数。
【讨论】:
不回答问题以上是关于async/await 会阻塞事件循环吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 工作原理之四-事件循环及异步编程的出现和 5 种更好的 async/await 编程方式(译)