首页 > 解决方案 > NodeJS 中的阻塞与非阻塞

问题描述

我们都知道 NodeJS 是单线程的,这意味着如果我们的代码中有 async/await 操作,节点会在执行其余代码之前等待它完成。因此,如果用户发出异步请求,其他用户也应该在发出请求之前等待它完成吗?

这里我创建了一个简单的示例,第一个路由使用异步函数,发送响应前需要 10 秒,第二个路由立即发送响应。

当我向第一个路由发送请求并等待响应时,我向第二个路由发送了另一个请求,即使第一个路由尚未完成执行代码,我也收到了响应。

为什么在这个例子中它是非阻塞的?

function sleep(){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(true)
    },10000)
  }).then(val=>val)
}


router.get('/route1',async (req,res)=>{
  const test = await sleep() 
  res.send('HELLO WORLD')
})

router.get('/route2',(req,res)=>{
  res.send("HELLO WORLD")
})

标签: javascriptnode.jsexpressasync-awaitnonblocking

解决方案


await仅阻止/暂停当前函数的执行,而不是整个解释器。事实上,当一个函数命中await函数内部的第一个函数时,该函数立即返回一个 Promise,并且在该函数(或发生的其他事件)可以自由运行之后的其他处理。

因此,在您的示例中,当它命中时await sleep(),该函数执行将暂停,直到await解析/拒绝并且包含async函数立即返回一个未实现的承诺。由于 Express withrouter.get()没有对返回的 Promise 做任何事情,它只是忽略它并将控制权返回给事件循环。稍后,您的第二个请求到达服务器,一个事件被放入 nodejs 事件队列,Express 被该事件调用,它为您的第二个路由处理程序提供服务。

因此,如果用户发出异步请求,其他用户也应该在发出请求之前等待它完成吗?

不。只有包含 的那个请求处理程序的一个实例await被挂起。通过事件循环在解释器和其他事件处理程序中的其他执行(例如其他传入请求)仍然可以发生,因此仍然可以处理其他请求,即使一个请求处理程序位于await. 这说明了如何await不阻塞或暂停整个解释器,只执行一个函数。

当我向第一个路由发送请求并等待响应时,我向第二个路由发送了另一个请求,即使第一个路由尚未完成执行代码,我也收到了响应。为什么在这个例子中它是非阻塞的?

只有第一条路线被await. 其他事件和其他传入请求仍然可以正常处理。


推荐阅读