简体   繁体   English

JavaScript多级承诺已跳过.then()

[英]JavaScript multi-level promises skipped .then()

I was having some problem with multi-level of promises. 我在多层承诺方面遇到了一些问题。 What I tried to do is first get list of receipt items under certain category, then for each receipt item, I get its detail & receipt ID, after I get the receipt ID, I search for the account ID. 我要尝试做的是首先获取特定类别下的收货清单,然后为每个收货清单获取明细和收据ID,获得收据ID之后,搜索帐户ID。 Then, I get the account details based on account ID. 然后,我根据帐户ID获取帐户详细信息。 Here is my code: 这是我的代码:

var query =  // get receipt items under certain category
    var outerPromise = query.once('value').then(data => {
        var promises = [];
        var datasetarr = [];

        data.forEach(snapshot => {
            var itemData = // get receipt item unique push ID

            var query = // get details of receipt items 
            var promise = query.once('value').then(data => { 
                var itemDetail = // get receipt item detail

                if(type == subtype){    
                    var receiptID = itemDetail.receiptID;

                    var query = // query receipts table by receiptID
                    return query.once('value').then(data => {   
                        data.forEach(snapshot => {
                            snapshot.forEach(childSnapshot => {
                                if(childSnapshot.key == receiptID){
                                    var accountKey = // get accountID

                                    var query = // query accounts table
                                    return query.once('value').then(data => {
                                        var accountDetail = data.val();
                                        var age = accountDetail.age;
                                        var gender = accountDetail.gender;
                                        console.log(age + ' ' + gender);
                                        datasetarr.push({age: age, gender: gender});
                                    });
                                }
                            });
                        });
                    }); 
                }
            });
            promises.push(promise);
        }); 

        return Promise.all(promises).then(()=> datasetarr);
});

I managed to print out the result from the console.log above. 我设法从上面的console.log打印出结果。 However, when I tried to print out here which is when the promise is done: 但是,当我尝试在此处打印出完成承诺时:

outerPromise.then((arr) => {
        console.log('promise done');
        for(var i = 0; i < arr.length; i++){
            console.log(arr[i].age + ' ' + arr[i].gender);
        }
    }); 

I get nothing here. 我什么都没有。 The console now is showing 'promise done' first before any other results I printed out above. 现在,控制台在我上面打印出的任何其他结果之前先显示“已完成承诺”。

Any ideas? 有任何想法吗? Thanks in advanced! 提前致谢!

I will provide a more detailed explanation in a couple of hours, I have a prior engagement which means I can't provide details now 我将在几个小时内提供更详细的说明,我已经事先约定,这意味着我现在无法提供详细信息

First step to a "easy" solution is to make a function to make an array out of a firebase snapshot, so we can use map/concat/filter etc “简单”解决方案的第一步是创建一个函数,以使用Firebase快照制作数组,因此我们可以使用map / concat / filter等

const snapshotToArray = snapshot => {
    const ret = [];
    snapshot.forEach(childSnapshot => {
        ret.push(childSnapshot);
    });
    return ret;
};

Now, the code can be written as follows 现在,代码可以编写如下

// get list of receipt items under category
var query // = // get receipt items under certain category
var outerPromise = query.once('value').then(data => {
    return Promise.all(snapshotToArray(data).map(snapshot => {
        var itemData // = // get receipt item unique push ID
        var query // = // get details of receipt items 
        return query.once('value').then(data => { 
            var itemDetail // = // get receipt item detail
            if(type == subtype){    
                var receiptID = itemDetail.receiptID;
                var query //= // query receipts table by receiptID
                return query.once('value').then(data => {   
                    return Promise.all([].concat(...snapshotToArray(data).map(snapshot => {
                        return snapshotToArray(snapshot).map(childSnapshot => {
                            if(childSnapshot.key == receiptID){
                                var accountKey //= // get accountID
                                var query //= // query accounts table
                                return query.once('value').then(data => {
                                    var accountDetail = data.val();
                                    var age = accountDetail.age;
                                    var gender = accountDetail.gender;
                                    console.log(age + ' ' + gender);
                                    return({age, gender});
                                });
                            }
                        }).filter(result => !!result);
                    }).filter(result => !!result)));
                }); 
            }
        });
    })).then([].concat(...results => results.filter(result => !!result))); 
});

To explain questions in the comments 解释评论中的问题

[].concat used to add the content of multiple arrays to a new array, ie [].concat用于将多个数组的内容添加到新数组,即

[].concat([1,2,3],[4,5,6]) => [1,2,3,4,5,6]

...snapshotToArray(data).map(etc

... is the spread operator, used as an argument to a function, it takes the iterable and "spreads" it to multiple arguments ...是散布运算符,用作函数的参数,它采用可迭代并将其“散布”为多个参数

console.log(...[1,2,3]) == console.log(1,2,3)

In this case snapshotToArray(data).map returns an array of arrays, to give a console log example 在这种情况下, snapshotToArray(data).map返回一个数组数组,以提供控制台日志示例

console.log(...[[1,2],[3,4]]) == console.log([1,2], [3,4])

adding the concat 添加连接

[].concat(...[[1,2],[3,4]]) == [].concat([1,2],[3,4]) == [1,2,3,4]

so it flattens a two level array to a single level, ie 所以它把一个两级数组展平到一个单层,即

console.log(...[[1,2],[3,4]]) == console.log(1,2,3,4)

So in summary, what that code fragment does is flatten a two level array 因此,总而言之,该代码片段的作用是将两级数组展平

filter(result => !!result)

simply "filters" out any array elements that are "falsey". 只需“过滤”掉所有“假”的数组元素。 As you have this condition 因为你有这种情况

if(childSnapshot.key == receiptID){

if that is false, the result will be undefined for that map - all other results will be an array, and even empty arrays are truthy - that's why the filtering is done so often! 如果那是假的,那么该map的结果将是undefined的-所有其他结果将是一个数组,甚至空数组都是真实的-这就是为什么如此频繁地进行过滤的原因! There's probably a better way to do all that, but unless you're dealing with literally millions of items, there's no real issue with filtering empty results like this 可能有更好的方法来完成所有这些操作,但是除非您要处理数以百万计的项目,否则像这样过滤空结果不会有真正的问题

End result is a flat array with only the Promises returned from the code within 最终结果是一个平面数组,其中仅从代码中返回了Promises

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM