(NestJS, TypeORM) Javascript promises : Finally 块在此之前被调用

(NestJS, TypeORM) Javascript promises : Finally block is called before then

我正在为用户资源创建一个带有 CRUD 操作的 API。因为 TypeORM 没有 return 将创建的用户插入数据库后,我执行 'findOne' 请求以提供用户名取回它。

为此,我使用 QueryRunner 在我的 UserService 中创建了一个事务。看起来像这样:

控制器

@Post()
  create(@Body() user: User) {
    return this.userService
      .createUser(user)
      .then((user) => {
        return user;
      })
      .catch(() => {
        throw new InternalServerErrorException('Could not create user');
      });
  }

服务

createUser(user: User): Promise<User | void> {
    const queryRunner = this.connection.createQueryRunner();

    return queryRunner
      .connect()
      .then(() => {
        queryRunner
          .startTransaction()
          .then(() => {
            queryRunner.manager
              .save(User, user)
              .then((user) => {
                queryRunner.manager
                  .findOne(User, {
                    username: user.username,
                  })
                  .then((user) => {
                    queryRunner
                      .commitTransaction()
                      .then(() => {
                        return Promise.resolve(user);
                      })
                      .catch((error) => {
                        console.log('Could not commit transaction : ', error);
                        return Promise.reject();
                      });
                  })
                  .catch((error) => {
                    console.log(
                      `Could not get user after insert, username : ${user.username}, error : ${error}`,
                    );
                    return Promise.reject();
                  });
              })
              .catch((error) => {
                console.log(
                  'Could not insert user into the database : ',
                  error,
                );
                queryRunner
                  .rollbackTransaction()
                  .then(() => {
                    console.log('Rolled back transaction');
                    return Promise.resolve();
                  })
                  .catch((error) => {
                    console.log('Could not rollback transaction : ', error);
                    return Promise.reject();
                  });
              });
          })
          .catch((error) => {
            console.log('Could not start transaction : ', error);
            return Promise.reject();
          });
      })
      .catch((error) => {
        console.log('Could not connect to database : ', error);
        return Promise.reject();
      })
      .finally(() => {
        queryRunner
          .release()
          .then((user) => {
            console.log('Released query runner for User transaction');
            return Promise.resolve(user);
          })
          .catch((error) => {
            console.log('Could not release queryRunner : ', error);
            return Promise.reject();
          });
      });
  }

此代码中有很多问题,我知道,但我是 javascript 世界的新手,不知道如何做得更好:

  1. 我在网上看了看,有些人把我正在做的事情(嵌套承诺)称为厄运金字塔,这是一种反模式,但我不知道该怎么做。
  2. 当我 运行 我的代码并发出创建用户的请求时,finally() 块在 then() 之前被调用,因此在我进行交易之前释放了我的 queryRunner。谁能告诉我为什么?
  3. 为了解决这个问题,我删除了 finally() 并在 then() 和 catch() 中进行了释放,但随后发生的事情是我的函数 return 在调用“startTransaction”之后编辑了并且没有' 之前执行 then(),所以发生的事情是我返回控制器并 return 在完成我的 UserService 函数 (createUser) 之前对用户做出响应。

希望您有足够的信息来帮助我,但如果需要,我很乐意添加更多详细信息。

谢谢,

关注你的问题

1- 尝试将您的函数转换为 async 并使用 async/await 这将使您更清楚地了解您尝试实现的逻辑

2- finallythen 之前被调用可能意味着发生了错误,尝试在 catch 中记录错误并调试它

这不是答案,我只是向您展示承诺金字塔的另一种方式,希望我的逻辑正确

async function createUser(user): Promise<any> {
    const queryRunner =  this.connection.createQueryRunner();

    await queryRunner.connect().catch(throwErr("couldn't connect") )

    await  queryRunner.startTransaction().catch(throwErr('could not start transaction'))

    const  User = await queryRunner.manager.save(user).catch(throwErr("could not save user") )

    await queryRunner.commitTransaction().catch(throwErr("could not complete transaction"))

    await queryRunner.release().catch(throwErr('Could not release queryRunner'))

    const foundedUser = await queryRunner.manager.findOne(User, {
        username: user.username,
    }).catch(throwErr("Could not connect to database"))

    return foundedUser
}

function throwErr(message){
    return (err)=> {throw new Error(message)}
}

感谢 scr2em 和 David Callanan,我将我的代码从嵌套承诺更改为 async/await,现在它可以正常工作了,这就是我所做的:

async createUser(user: User): Promise<User | void> {
    const action = `(Create user : ' ${user.username}) `;
    const queryRunner = this.connection.createQueryRunner();

    await queryRunner.connect().catch((error) => {
      console.log(action + 'Could not connect to database : ', error);
      return Promise.reject();
    });
    await queryRunner.startTransaction().catch((error) => {
      console.log(action + 'Could not start transaction : ', error);
      return Promise.reject();
    });
    await queryRunner.manager.save(User, user).catch(async (error) => {
      console.log(action + 'Could not insert user into the database : ', error);
      await queryRunner.rollbackTransaction().catch((error) => {
        console.log(action + 'Could not rollback transaction : ', error);
        return Promise.reject();
      });
      return Promise.reject();
    });
    const userResult = await queryRunner.manager
      .findOne(User, { username: user.username })
      .catch(async (error) => {
        console.log(
          action +
            `Could not get user after insert, username : ${user.username}, error : ${error}`,
        );
        await queryRunner.rollbackTransaction().catch((error) => {
          console.log(action + 'Could not rollback transaction : ', error);
          return Promise.reject();
        });
        return Promise.reject();
      });
    await queryRunner.commitTransaction().catch((error) => {
      console.log(action + 'Could not commit transaction : ', error);
      return Promise.reject();
    });
    await queryRunner.release().catch((error) => {
      console.log(action + 'Could not release queryRunner : ', error);
      return Promise.reject();
    });
    return Promise.resolve(userResult);
  }

希望对其他人有所帮助。