如何在节点中真正使耗时的请求异步



我正在尝试扩展我的nodejs应用程序,以便它能够同时有效地处理多个请求。实现这一点的一种方法是通过代码优化,我想知道如何使耗时的请求异步,承诺是唯一的方法吗?还是有其他机制可以实现同样的目的?

我已经将promise用于异步任务,但就我对promise的理解而言,真正的异步部分是then和catch处理程序。当创建promise时,executor函数将由主线程执行,直到它完成一些异步任务(setTimeout等)。

发送电子邮件的示例代码

app.route('/api/contact/sendEmail')
.post((req, res) =>{
sendEmail(req).then( () =>{
res.status(200);
res.json({
sent: true
});
}).catch(emailError=> {
//Custom error send bad request.
if(emailError.code === 900) {
res.status(400);
res.json({
errorCode: emailError.code,
message: emailError.message
});
}else {
res.status(500);
res.json({
errorCode: emailError.code
});
}
});
});

线程不会被阻止发送响应,但直到sendEmail没有到达实际的异步部分,主线程才会被阻止

很难回答您的问题,因为您没有提供有关正在使用的库/函数的详细信息,例如sendMail函数来自哪里,app是什么,以及您认为某个函数在什么时候被阻塞。

但是,通常情况下,您在Node中的代码。JS总是在主线程中执行。这意味着,js文件的每一行都在主线程中,无论是否有"异步"。

现在,要真正允许某些东西是"异步"的(即:在执行其他代码的同时执行),必须有一种方法将这些东西推到另一个线程中执行。这就是Node中实际发生的事情。JS在引擎盖下。节点。JS使用libuv/libev来实现一个事件循环来处理任务。它还具有许多后台/工作线程(默认为4个),它们执行阻塞任务,例如网络或文件I/O。

但是,这是从Node中抽象出来的。JS开发人员,因为它隐藏在相应的模块的实现中。例如,内置文件系统或网络模块将在后台线程中执行它们的任务(除非您使用-sync函数变体之一)。如果您使用的是第三方模块,这取决于它是否是用C/C++编写的,并使用libuv访问工作线程和进行后台处理。如果不是,那么你的第三方模块将在主线程上执行与你的代码相同的代码,如果是,那么执行实际上是在后台线程中"异步"/完成的。

还请参阅这个信息丰富的线程:单线程非阻塞IO模型如何在Node.js 中工作

这对你有什么帮助
基本上,我想告诉您,这完全取决于您正在使用的功能/模块,以及它们是否作为后台操作(使用libuv)实现。最重要的是,你不能自己使任何东西异步/同步,你必须使用函数/模块实现的任何东西。

为了完整起见,我想提到Node。JS 11引入了worker_threads模块,它允许在javascript代码中使用线程,从而允许您在后台线程中放置一些东西,而不会阻塞主线程。请注意,模块的稳定性仍然是"实验性的"。

旁注
您真的确定您的代码正在阻塞主线程吗?因为如前所述,网络IO无论如何都发生在后台线程中,所以sendMail不太可能阻塞主线程(假设sendMail的工作是执行网络IO)。你是怎么发现它在阻塞的?

最新更新