(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 世界的新手,不知道如何做得更好:
- 我在网上看了看,有些人把我正在做的事情(嵌套承诺)称为厄运金字塔,这是一种反模式,但我不知道该怎么做。
- 当我 运行 我的代码并发出创建用户的请求时,finally() 块在 then() 之前被调用,因此在我进行交易之前释放了我的 queryRunner。谁能告诉我为什么?
- 为了解决这个问题,我删除了 finally() 并在 then() 和 catch() 中进行了释放,但随后发生的事情是我的函数 return 在调用“startTransaction”之后编辑了并且没有' 之前执行 then(),所以发生的事情是我返回控制器并 return 在完成我的 UserService 函数 (createUser) 之前对用户做出响应。
希望您有足够的信息来帮助我,但如果需要,我很乐意添加更多详细信息。
谢谢,
关注你的问题
1- 尝试将您的函数转换为 async
并使用 async/await
这将使您更清楚地了解您尝试实现的逻辑
2- finally
在 then
之前被调用可能意味着发生了错误,尝试在 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);
}
希望对其他人有所帮助。
我正在为用户资源创建一个带有 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 世界的新手,不知道如何做得更好:
- 我在网上看了看,有些人把我正在做的事情(嵌套承诺)称为厄运金字塔,这是一种反模式,但我不知道该怎么做。
- 当我 运行 我的代码并发出创建用户的请求时,finally() 块在 then() 之前被调用,因此在我进行交易之前释放了我的 queryRunner。谁能告诉我为什么?
- 为了解决这个问题,我删除了 finally() 并在 then() 和 catch() 中进行了释放,但随后发生的事情是我的函数 return 在调用“startTransaction”之后编辑了并且没有' 之前执行 then(),所以发生的事情是我返回控制器并 return 在完成我的 UserService 函数 (createUser) 之前对用户做出响应。
希望您有足够的信息来帮助我,但如果需要,我很乐意添加更多详细信息。
谢谢,
关注你的问题
1- 尝试将您的函数转换为 async
并使用 async/await
这将使您更清楚地了解您尝试实现的逻辑
2- finally
在 then
之前被调用可能意味着发生了错误,尝试在 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);
}
希望对其他人有所帮助。