Как обрабатывать вложенные обещания в NodeJS

Я относительно новичок в 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?

Привет и спасибо!

Рефакторинг с помощью асинхронный / ожидание будет более читаемым, и код будет выглядеть как синхронизация, но он будет вести себя как асинхронный.

squeekyDave 14.11.2018 13:10

можешь дать мне что-то как псевдокод? Как я могу изменить это на асинхронный и ждать?

mcAngular2 14.11.2018 13:15

@ mcAngular2 вы можете попробовать использовать async / await здесь. Делает жизнь намного проще!

Abrar 14.11.2018 14:30
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
158
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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?

mcAngular2 14.11.2018 13:12

Что-то вроде этого. Надеюсь это поможет.,

Estus Flask 14.11.2018 13:19

Просто оберните приведенный выше код в асинхронную функцию yourFuncName () {}; Подробнее о асинхронный / ожиданиеdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

squeekyDave 14.11.2018 13:21
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().
Estus Flask 14.11.2018 13:20
Ответ принят как подходящий

Сделайте это просто так:

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 ...
})();

Другие вопросы по теме