NestJS+TypeORM场景下Promise finally提前执行及异步嵌套问题求助
问题解决方案
核心问题根源
- 你遇到的所有问题根源是嵌套Promise没有被return到外层Promise链:内部的
queryRunner.startTransaction()等操作是独立的Promise,没有被外层的.then返回,导致外层Promise不等内部逻辑执行完成就进入finally/直接resolve,才出现queryRunner提前释放、函数提前返回的问题。 - 多层Promise嵌套的回调金字塔可以通过ES7的
async/await语法完全解决,代码可读性会大幅提升。
优化后代码
Service 代码
async createUser(user: User): Promise<User> { const queryRunner = this.connection.createQueryRunner(); try { // 建立数据库连接 await queryRunner.connect(); // 开启事务 await queryRunner.startTransaction(); // 插入用户数据 const savedUser = await queryRunner.manager.save(User, user); // 查询插入后的完整用户数据 const fullUser = await queryRunner.manager.findOne(User, { username: savedUser.username }); // 提交事务 await queryRunner.commitTransaction(); return fullUser; } catch (error) { // 任意步骤报错都回滚事务 console.error('事务执行失败:', error); await queryRunner.rollbackTransaction(); throw new Error('创建用户失败'); } finally { // 无论成功失败都释放queryRunner await queryRunner.release(); console.log('User事务queryRunner已释放'); } }
Controller 代码(可同步简化)
@Post() async create(@Body() user: User) { try { return await this.userService.createUser(user); } catch (e) { throw new InternalServerErrorException('Could not create user'); } }
对应问题解决说明
- 回调金字塔问题:改用async/await语法后,所有异步操作按顺序平铺书写,没有嵌套,逻辑一目了然,完全规避了回调地狱问题。
- finally提前执行问题:async/await会自动等待前一个异步操作完成才执行后续逻辑,finally块会等try/catch里的所有异步操作全部执行完成后才触发,不会再出现提前释放queryRunner的情况。
- 函数提前返回问题:async函数会返回一个Promise,只有当函数内所有await操作完成、return执行或者抛出错误时,Promise才会变更状态,控制器会一直等待createUser执行完成再返回响应。
额外优化建议
实际上TypeORM的save方法默认会返回插入后的完整实体,如果你是因为自增主键、创建时间等自动生成字段没有返回,大概率是实体的字段装饰器配置问题,比如主键没有加@PrimaryGeneratedColumn(),自动生成字段没有加@CreateDateColumn()等,配置正确的话可以省去二次查询的步骤,提升接口性能。
内容的提问来源于stack exchange,提问作者Varadus
相关产品推荐
相关产品推荐

