Я относительно новичок в Promises, поэтому надеюсь, что вы можете мне помочь. У меня такой код:
bcrypt.genSalt(10)
.then((salt) =>{
return bcrypt.hash(newUser.password, salt)
})
.then((hash)=>{
newUser.password = hash;
return mariaDB.pool.getConnection()
})
.then((conn)=>{
conn.beginTransaction()
.then() //here I'm doing some database request
.catch((err)=>{
console.info(err)
return conn.rollback() //where is this Promise handled?
})
})
.catch((err)=>{
res.json({error: err})
})
Я получаю объект newUser, который сначала передаю в bcrypt, чтобы зашифровать свой пароль. Затем мне нужно сделать транзакцию в моей базе данных MariaDB. Но верны ли такие «вложенные обещания»? Есть ли лучшее решение? Где обрабатывается обещание return conn.rollback?
Привет и спасибо!
можешь дать мне что-то как псевдокод? Как я могу изменить это на асинхронный и ждать?
@ mcAngular2 вы можете попробовать использовать async / await здесь. Делает жизнь намного проще!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


return conn.rollback() //where is this Promise handled?
не обрабатывается, это проблема этого фрагмента. Вложенные обещания должны быть связаны, чтобы поддерживать надлежащий поток управления, т.е. возвращаться из обратных вызовов then и catch:
.then((conn)=>{
return conn.beginTransaction()
...
Вложенное обещание требуется, потому что conn должен быть доступен в обратных вызовах then. Более удобный способ справиться с этим - async..await, он позволяет сгладить вложенные обещания:
try {
const salt = await bcrypt.genSalt(10)
const hash = await bcrypt.hash(newUser.password, salt)
newUser.password = hash;
const conn = await mariaDB.pool.getConnection()
try {
conn.beginTransaction()
// ...
} catch (err) {
await conn.rollback()
}
} catch (err) {
res.json({error: err})
}
Хорошо было бы повторно выдать ошибку после rollback, потому что ясно, что в этот момент что-то пошло не так.
Как я могу изменить этот suing async и await?
Что-то вроде этого. Надеюсь это поможет.,
Просто оберните приведенный выше код в асинхронную функцию yourFuncName () {}; Подробнее о асинхронный / ожиданиеdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
bcrypt.genSalt(10)
.then((salt) =>{
return bcrypt.hash(newUser.password, salt)
})
.then((hash)=>{
newUser.password = hash;
return mariaDB.pool.getConnection()
})
.then((conn)=>{
return dbops(conn)
})
.catch((err)=>{
res.json({error: err})
})
// добавлена новая функция db ops
function dbops(conn){
return new Promise(function(resolve,reject){
conn.beginTransaction()
.then((data)=>{
//db stuff
resolve("db stuff done")
}).catch((err)=>{
console.info(err)
conn.rollback()
reject(err)
})
})}
Надеюсь, что это поможет вам.
new Promise - это антипаттерн многообещающей конструкции. Обещание уже есть, новое создавать не нужно. Также не учитываются обещания rollback().
Сделайте это просто так:
bcrypt.genSalt(10)
.then(salt => bcrypt.hash(newUser.password, salt))
.then(hash => {
newUser.password = hash;
return mariaDB.pool.getConnection()
})
.then(conn => {
return conn.beginTransaction()
.then(() => {
// here I'm doing some database request
})
.catch( err => {
conn.rollback();
throw new Error(err); // this error will be cathed on bottom catch
});
})
.catch(err => res.json({error: err}))
Переписывание с асинхронный / ожидание (облегчение вашей жизни за счет избавления от всех этих вложенных обещаний, спасибо позже!) Будет выглядеть так:
try {
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(newUser.password, salt);
newUser.password = hash;
const conn = await mariaDB.pool.getConnection();
try {
const transaction = await conn.beginTransaction();
// your db calls
} catch (err) {
console.info(err);
return conn.rollback();
}
} catch (err) {
res.json({error: err})
}
Убедитесь, что вы заключили этот блок в функцию async. Например, для функции автоматического вызова используйте:
(async() => {
// the block of code using await ...
})();
Рефакторинг с помощью асинхронный / ожидание будет более читаемым, и код будет выглядеть как синхронизация, но он будет вести себя как асинхронный.