Node.js中Promise并发执行耗时异常及NaN问题求助
问题原因分析
1. MongoDB连接池冷启动的影响
Node.js的MongoDB驱动默认用连接池管理数据库连接。第一次执行数据库操作时,驱动需要完成TCP握手、认证、初始化连接池等操作,这部分是额外的冷启动开销:
- 先跑并发代码(i)时,所有Promise会同时触发数据库请求,此时连接池尚未建立,每个请求都要等待新连接创建,反而因连接初始化的竞争拉长总耗时;
- 接着执行串行代码(ii)时,连接池已经暖启动,串行请求可直接复用已有连接,耗时更短;
- 调换执行顺序后,串行代码(ii)先触发冷启动,完成后并发代码(i)直接用现成连接,自然(ii)耗时更长。
2. 并发请求的资源竞争与调度开销
MongoDB对并发请求的处理能力有上限,大量请求同时涌入时,数据库会进行内部排队;同时Node.js事件循环调度大量异步Promise时,也会产生额外的上下文切换开销。反而串行请求因依次执行,不会触发数据库限流排队,在连接池就绪后,整体耗时更稳定。
3. 'seedRoles in NAN'的根源
这个输出几乎可以肯定是计时逻辑的变量问题:
- 比如用于计算耗时的
startTime变量作用域错误(用了全局变量被其他异步操作篡改),或是在异步流程中未正确初始化就做减法计算(比如Date.now() - startTime里startTime未赋值)。 - 典型错误示例:
let startTime; // 全局变量易被篡改 async function seedRoles() { // 若此处被异步中断,startTime可能未赋值就执行后续代码 startTime = Date.now(); await Promise.all(roles.map(role => db.collection('roles').insertOne(role))); console.log(`seedRoles in ${Date.now() - startTime}ms`); }
当并发场景下变量被意外覆盖,或是异步流程中startTime未正确设置,就会出现NaN的输出。
内容的提问来源于stack exchange,提问作者Akrem Gomri
相关产品推荐
相关产品推荐

