非async函数返回Promise且允许同步抛错是否为合理技术模式?
关于TypeORM中
EntityManager.count()非async设计的疑问与解决方案 核心问题拆解
EntityManager.count()并非async函数,但返回Promise,内部的setFindOptions()可能同步抛出错误- 同步错误会直接跳过
await逻辑,如果在Promise.all中使用,后续异步错误可能因未被捕获触发未处理的Promise拒绝,进而导致服务器崩溃 - 同为查询方法的
find()是async函数,这种设计不一致性让人疑惑其意图
设计意图分析
TypeORM部分方法采用非async但返回Promise的写法,主要源于两个原因:
- 历史兼容性:早期TypeORM版本中,部分方法基于回调或手动构建Promise实现,后续迁移到async/await时,部分方法保留了原有实现逻辑
- 微小性能优化:
async函数会额外生成一层Promise包装,对于能直接返回已有Promise的场景,手动返回Promise可减少这一层异步开销,但实际收益非常有限
风险规避与解决方案
这种设计确实存在隐患,你可以通过以下方式处理:
- 手动包装为async函数:
这样即使内部有同步错误,也会被async函数捕获并转为rejected状态的Promise,统一通过const safeCount = async (entity: any, options?: any) => { return entityManager.count(entity, options); };await或.catch()处理 - 提前参数校验:调用
count()前自行校验查询参数合法性,避免触发setFindOptions()的同步错误 - 全局异常兜底:在服务器端添加全局监听,防止未处理的Promise拒绝导致崩溃:
process.on('unhandledRejection', (reason, promise) => { console.error('未处理的Promise拒绝:', reason); // 可根据业务需求添加日志、告警或恢复逻辑 });
总结
返回Promise的函数并非必须是async函数,但async函数能统一同步/异步错误的处理逻辑,减少意外情况。TypeORM的这种不一致设计更多是历史遗留问题,而非最佳实践。你可以放心使用包装后的async版本规避同步抛错风险,不会影响原有功能。
内容的提问来源于stack exchange,提问作者queueueue
相关产品推荐
相关产品推荐

