在 Node/Express 服务器中使用 async/await 是个坏主意吗?

Is it a bad idea to use async/await in a Node/Express server?

我有一个 NodeJS/Express 网络应用程序,其中 TypeOrm 用于许多数据库功能。为了避免回调地狱,我通常使用 async/await 从我的端点方法调用和等待数据库操作。
不过,我听说像 fs.readFileSync 这样的方法应该始终避免,因为它们会阻塞并会强制所有其他请求等待。这也适用于 async/await 吗?我是否必须使用承诺和回调来获得不错的多用户性能?

您不应该使用 *Sync 函数的原因是它们会阻塞事件循环。这会导致您的应用程序在执行同步功能时变得无响应。

Promises 可以帮助您在处理异步代码时避免回调地狱问题。此外,async/await 语法允许您编写看起来像同步代码的异步代码。所以使用 async 和 await 是完全没问题的。

Sync 函数真正地 BLOCK 事件循环,直到 io 完成。但另一方面 async-await 只是 Promise 链的语法糖。它实际上不是同步的,它只是看起来像。这是您需要了解的最大区别。

但是,async-await 使承诺过于连续会引入一些问题。

例如,两个独立的承诺应该与 Promise.all 并行执行,但是当您使用 async-await 时,您倾向于

await func1();
await func2();

所以,从逻辑上讲,你可能会自己制造瓶颈。但在语法上它没有像 Sync 那样的问题。

你可以看看 ES5 transpilation using Babel REPL,你可能会理解得更好一些。

I've heard, however, that methods like fs.readFileSync should always be avoided, since they are blocking and will force all other requests to wait.

大部分情况下是这样。

请记住,您的服务器不会 运行 在单个管道上。相反,您并排使用 cluster API 到 运行 多个工作进程(其中服务器 CPU 的核心数量限制了工作进程的数量应该是 运行).

实际上,即使单个事件循环被同步 IO 阻塞并且分配给同一循环的其他请求被迫等待,其他工作进程仍然能够处理传入的请求。

另一方面,如果您发出一个请求 await 一个 IO 操作,循环能够拾取另一个请求并处理它。但是,需要权衡取舍。

假设第一个请求来了,你await一个fs.readFile。第二个请求来了,它被处理了。但是第二个请求不等待任何 IO,而是一个 CPU 绑定操作(可能是繁重的计算?)。由第一个请求触发的 IO 操作完成,但它必须 等待 直到第二个请求完成,然后事件循环才能继续执行并发送回响应。

Do I have to use promises and callbacks to get decent multi-user performance?

一个简单的答案是,但是,要小心并监控您的应用程序,以免陷入陷阱(例如 mixing IO requests with CPU intensive tasks 异步 IO 的性能从客户的角度来看可能更糟)。

在 Node.js 语法中使用 async/await 优于备选方案,后者是股票承诺,尤其是回调。它允许更简洁的代码,更容易理解和维护。在过去,我们曾经不得不使用 babel 来转译以访问这些内容,但它们现在已经在 Node 中使用了很长时间,所以我建议人们使用它们。