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,等等。

我开始怀疑,如果我 awaiting 对数据库的一些 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)。一旦调用堆栈为空,这些作业就会执行(因此通过事件循环,一旦调用堆栈为空,就会将新作业推送到调用堆栈)。 另外,在第一个示例中,您有优势来操作 responsejson 对象。我的意思是,迭代对象或获取其他信息。【参考方案2】:

异步函数返回一个promise,你传入请求和响应,我会改变 res.json(数据) 到 返回 res.json(数据)

当异步函数返回值时,promise 被解析,如果函数包含错误,promise 被拒绝,只是为了清洁返回 res.json(data) 将解析函数。

【讨论】:

不回答问题

以上是关于async/await 会阻塞事件循环吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Async/Await 仍然阻塞 UI?

JavaScript 工作原理之四-事件循环及异步编程的出现和 5 种更好的 async/await 编程方式(译)

我可以使用 async/await 来等待 JavaScript 中的多个事件吗?

kestrel vs async await c#

async await 异步编程杂记

[译]async/await中使用阻塞式代码导致死锁