Возвращает нулевое значение, когда я пытаюсь суммировать цену в обещании

#javascript #scope #es6-promise

#javascript #область действия #es6-обещание

Вопрос:

Я пытаюсь извлечь данные из API (firebase) и возвращаю правильные данные, но когда я пытаюсь определить окончательную цену в обещании, я продолжаю получать значение 0. Я пытался перемещать исходную переменную, чтобы изменить область видимости, и пока ничего не помогло.

 const staffTotalPrices = (eventFirebaseKey) => new Promise((resolve, reject) => {
  eventStaff.getEventStaff(eventFirebaseKey).then((staffArray) => {
    let staffTotal = 0;
    staffArray.forEach((staff) => {
      staffData.getSingleStaff(staff.staffUid).then((staffObject) => {
        staffTotal  = parseInt(staffObject.price, 10);
        return staffTotal;
      });
    });
    resolve(staffTotal);
  }).catch((error) => reject(error));
});
  

Я помещал его в пустой массив, затем выполнял метод .reduce array для добавления итогов, но мне приходится устанавливать тайм-аут при его вызове / уменьшении, чтобы дождаться ответа API

Ответ №1:

В вашем forEach цикле вы вызываете асинхронную функцию, но не ожидаете ее результата. Итак, вы вызываете resolve(staffTotal) перед любым из staffData.getSingleStaff разрешенных.

Вы могли бы, например, сделать a Promise.all() , который выполнит все обещания и разрешит с помощью массива результатов.

 const staffTotalPrices = (eventFirebaseKey) => new Promise((resolve, reject) => {
  eventStaff.getEventStaff(eventFirebaseKey)
    //execute getSingleStaff for all elements in the array and resolve when all are resolved
    .then(staffArray => Promise.all(staffArray.map(staff => staffData.getSingleStaff(staff.staffUid))))
    //sum up the prices in the staffObjects array with reduce
    .then(staffObjects => staffObjects.reduce((a,c) => parseInt(a.price, 10)   parseInt(c.price, 10), 0))
    //resolve the promise with the sum
    .then(totalStaff => resolve(totalStaff));
    .catch((error) => reject(error));
});
  

Другой возможностью было бы ведение подсчета разрешенных обещаний внутри цикла forEach. И как только все обещания будут выполнены, также разрешите внешнее обещание. Но тогда, конечно, вам также нужно будет перехватить отклонение внутренних обещаний, так как в противном случае, если одно из них отклонит ваше обещание, оно может остаться в состоянии ожидания.

 const staffTotalPrices = (eventFirebaseKey) => new Promise((resolve, reject) => {
  eventStaff.getEventStaff(eventFirebaseKey).then((staffArray) => {
    let staffTotal = 0; let resolveCounter = 0;
    staffArray.forEach((staff) => {
      staffData.getSingleStaff(staff.staffUid)
        .then((staffObject) => {
          staffTotal  = parseInt(staffObject.price, 10);
          if (  resolveCounter == staffArray.length) 
            resolve(staffTotal);
        })
        .catch(e => reject(e));
    });
  }).catch((error) => reject(error));
});