JavaScript多个promise会导致null

时间:2017-08-01 10:36:55

标签: javascript firebase asynchronous firebase-realtime-database promise

我在JavaScript承诺方面遇到了一些问题。这是我的代码:

receiptID

我添加了一些评论来解释我想要做的事情。现在的问题是我得到promise variable并创建另一个console.log并将其推入promise数组,.then()会打印出结果。

然而,在我注释掉该行并尝试在{{1}}打印出结果后,打印出promise promise消息,但是没有来自数组的结果,也没有错误消息,这意味着异步执行没有正确完成。

任何想法如何解决这个问题?先谢谢!

1 个答案:

答案 0 :(得分:1)

您的代码中没有任何东西在等待那些从属承诺。因为您没有从then处理程序返回任何内容,所以当处理程序完成时,promise then返回会立即得到解决。所以你正在等待第一级承诺(你进入promises的那些承诺),而不是那些查询收据细节的承诺。

承诺的关键之一是then会返回新的承诺;它是一个管道,其中每个then(和catch)处理程序都可以修改传递的内容。 then(或catch)返回的承诺将使用then处理程序的返回值解析,如果它不是类似承诺(“可能”)的值,或者是奴隶承诺返回then处理程序,如果它像承诺一样(“可以”)。

所以你应该从等待收据的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);
    }
});

这可以用箭头函数的简洁形式更简洁地写出来,但这有时会妨碍清晰。