Несколько обещаний JavaScript, приводящих к нулю

1

У меня возникла проблема с обещаниями JavaScript. Вот мой код:

//removed code

Я добавил несколько комментариев, чтобы объяснить, что я пытаюсь сделать. Проблема теперь в точке, где я получаю receiptID и создал другую promise variable и receiptID ее в массив обещаний, console.log выводит результат.

Однако после того, как я прокомментировал эту строку и попытался распечатать результат в .then(), сообщение с обещанием было распечатано, но результат не получен из массива или сообщение об ошибке, что означает, что асинхронное выполнение не выполняется должным образом.

Любые идеи, как это исправить? Заранее спасибо!

  • 0
    Возможный дубликат Почему значение undefined в .then () связано с Promise?
  • 0
    Избегайте Promise конструктора антипаттерна !
Показать ещё 5 комментариев
Теги:
firebase
asynchronous
promise
firebase-realtime-database

1 ответ

1

Ничто в коде не ждет этих подчиненных обещаний. Потому что вы ничего из вашего не возвращает then обработчик, обещание then возвращается немедленно решена, когда завершает обработчик. Итак, вы ждете обещаний первого уровня (те, которые вы вставляете в promises), но не те, которые запрашивают информацию о получении.

Одна из ключевых моментов в обещаниях - это then что дает новое обещание; это трубопровод, где каждый thencatch обработчик) может изменить то, что проездом. Обещание, возвращенное к тому then (или catch), будет разрешено с возвращаемым значением обработчика then, если это не похожее на обещание ("thenable") значение или slav, обещающее возврат обработчика then если он обещает -подобный ("thenable").

Таким образом, вы должны распространять что - то из вашего then обработчика, который ждет поступлений; вероятно, результат Promise.all. Я бы сделал это, разбив это на отдельные функции (по крайней мере два: тот, который получает внешний уровень, что бы это ни было, и тот, который получает квитанции для этого уровня).

Также обратите внимание, что нет никаких оснований для явного создания нового обещания на вашем верхнем уровне. У вас уже есть один: один once.

Если я понимаю, что вы пытаетесь сделать правильно, я немного реорганизовал здесь, чтобы получить информацию о квитанции на основе элементов, а затем сделать один звонок, чтобы получить квитанции вместо вызова на элемент, и получить информацию о филиале от квитанции. См. Комментарии:

const promiseDataList =
    // Get all receipt items for the category
    firebase.database().ref('receiptItemIDsByCategory').child(category).once('value').then(itemIds => {
        // Build a map of receipt info keyed by receipt ID by getting all of the items and, as
        // we get them, storing the receipt info in the map
        const receiptMap = new Map();
        return Promise.all(itemIds.map(itemSnapshot => {
            // Get the details of each receipt into a map keyed by receipt ID; since a receipt
            // can have multiple items, be sure to check the map before adding a new entry
            return firebase.database().ref('receiptItems').child(itemSnapshot.key).once('value').then(item => {
                const itemDetail = item.val();
                const price = itemDetail.price;
                const quantity = itemDetail.quantity;
                const itemTotal = price * quantity;
                const receiptEntry = receiptMap.get(itemDetail.receiptID);
                if (receiptEntry) {
                    // We already have this receipt, add to its total
                    receiptEntry.total += itemTotal;
                } else {
                    // New receipt
                    receiptMap.set(itemDetail.receiptID, {id: itemDetail.receiptID, total: itemTotal});
                }
            });
        })).then(() => {
            // We have the map of receipts we want info for; get all receipts so we can filter
            // for only the ones we want. (Note: Surely we could use the keys from receiptMap to
            // limit this Firebase query?)
            return firebase.database().ref('receipts').once('value').then(receipts => {
                // Filter out the irrelevant receipts (again, Firebase perhaps could do that for us?)
                // and then map the remaining ones to objects with the desired information
                return receipts.filter(receipt => receiptMap.has(receipt.key)).map(receipt => {
                    const branchDetail = receipt.val().branch;
                    const branchName = branchDetail.branchName;
                    const branchAddress = branchDetail.branchAddress;
                    console.log(branchName + ' ' + branchAddress + ' ' + receipt.total);
                    return {branchName, branchAddress, total: receipt.total};
                });
            });
        }); 
    }); 

promiseDataList.then(arr => {
    console.log('promise done');
    for (var i = 0; i < arr.length; i++) {
        console.log(arr[i].branchName + ' ' + arr[i].branchAddress + ' ' + arr[i].total);
    }
});

Это может быть написано немного более кратко с краткой формой функций стрелок, но это может иногда мешать ясности.

  • 0
    Извините, но я новичок в этом и еще не знаком с обещанием. Поэтому для «некоторой подготовки» эту часть я должен заменить на query.once и data.forEach для части itemKey. Тогда как быть с запросом возврата, который находится в третьей строке решения?
  • 0
    @DeniseTan: На самом деле, «некоторая подготовка» будет такой, как var itemData = snapshot.val(); var itemKey = snapshot.key; и тому подобное. firebase...once() будет частью query . Если вы не знакомы с обещаниями, я настоятельно рекомендую сначала проработать несколько более простых сценариев и подготовиться к этой задаче.
Показать ещё 14 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню