#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));
});