Ловля ошибок обещания в обратном вызове другого обещания - PullRequest
0 голосов
/ 03 ноября 2018

Код ниже работает как ожидалось. Если вызывается функция начисления, функция извлекает соответствующий объект заявки из firestore и затем возвращает его обратно клиенту.

Если тикет не существует, функция выдает HttpsError с сообщением об ошибке, которое будет проанализировано клиентом.

exports.charge = functions.https.onCall(data => {
  return admin.firestore().collection('tickets').doc(data.ticketId.toString()).get()
    .then((snapshot) => {
      return { ticket: snapshot.data() }
    })
    .catch((err) => {
      throw new functions.https.HttpsError(
        'not-found', // code
        'The ticket wasn\'t found in the database'
      );
    });
  });

Проблема возникает после этого. Теперь мне нужно зарядить пользователя с помощью Stripe, который является еще одним асинхронным процессом, который вернет Promise. Для оплаты требуется информация о ценах, полученная с помощью первого асинхронного метода, поэтому ее необходимо вызывать после получения snapshot.

exports.charge = functions.https.onCall(data => {
  return admin.firestore().collection('tickets').doc(data.ticketId.toString()).get()
    .then((snapshot) => {
      return stripe.charges.create(charge) // have removed this variable as irrelevant for question
        .then(() => {
          return { success: true };
        })
        .catch(() => {
          throw new functions.https.HttpsError(
            'aborted', // code
            'The charge failed'
          );
        })
    })
    .catch(() => {
      throw new functions.https.HttpsError(
        'not-found', // code
        'The ticket wasn\'t found in the database'
      );
    });
  });

Моя проблема с отловом ошибок в новом запросе charge. Кажется, что в случае сбоя зарядки он успешно вызывает первый «прерванный» улов, но затем он передается родительскому улову, и ошибка переопределяется, и приложение видит ошибку «тикет не найден».

Как я могу остановить это? Мне нужно отловить обе ошибки по отдельности и выдать HttpsError за каждую.

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

Как правило, такие проблемы могут быть решены добавлением узла status и последующим сцеплением с последним блоком then. Вы можете попробовать что-то вроде следующего

exports.charge = functions.https.onCall(data => {
  return admin.firestore().collection('tickets').doc(data.ticketId.toString()).get()
    .then((snapshot) => {
      return stripe.charges.create(charge)
        .then(() => {
          return { success: true };
        })
        .catch(() => {
             return {
                status : 'error', 
                error : new functions.https.HttpsError(
            'aborted', // code
            'The charge failed',
            { message: 'There was a problem trying to charge your card. You have NOT been charged.' }
          )};
        })
    })
    .catch(() => {
      return {
         status : 'error',
         error : new functions.https.HttpsError(
        'not-found', // code
        'The ticket wasn\'t found in the database',
        { message: 'There was a problem finding that ticket in our database. Please contact support if this problem persists. You have NOT been charged.' }
      )};
    }).then((response) => {
         if(response.status === 'error') throw response.error;
         else return response;
    });
  });
0 голосов
/ 03 ноября 2018

Не вкладывайте then внутрь другого then для нескольких предметов работы:

work1
.then((work1_results) => {
    return work2.then((work2_results) => {
        // this is bad
    })
})

Вместо этого выполняйте всю свою работу в виде последовательности:

work1
.then((work1_results) => {
    return work2
})
.then((work2_results) => {
    // handle the results of work2 here
})

Вы можете хранить промежуточные результаты в переменных более высокого уровня, если вам нужно накапливать данные между вашими обратными вызовами.

...