跳过JavaScript多级承诺.then()

时间:2017-08-06 01:05:56

标签: javascript asynchronous promise

我遇到了多层承诺的问题。我试图做的是首先得到某些类别下的收据项目清单,然后对于每个收据项目,我得到它的详细信息和收据ID,收到收据ID后,我搜索帐户ID。然后,我根据帐户ID获取帐户详细信息。这是我的代码:

button

我设法打印出上面button1.backgroundColor = UIColor.gray button2.backgroundColor = UIColor.gray 的结果。但是,当我试图在这里打印时,承诺就完成了:

<div class="h3"><span class="glyphicon glyphicon-tags" aria-hidden="true"></span></div>

我什么都没得到。在我上面打印出的任何其他结果之前,控制台现在首先显示“承诺完成”。

有什么想法吗?先谢谢!

1 个答案:

答案 0 :(得分:3)

  

我将在几个小时内提供更详细的解释,我之前已经参与,这意味着我现在无法提供详细信息

第一步到'#34; easy&#34;解决方案是创建一个函数,使一个数组从firebase快照中生成,因此我们可以使用map / concat / filter等

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

现在,代码可以写成如下

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

在评论中解释问题

[].concat用于将多个数组的内容添加到新数组中,即

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

...snapshotToArray(data).map(etc

...是扩展运算符,用作函数的参数,它采用可迭代和&#34;传播&#34;它到多个参数

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

在这种情况下,snapshotToArray(data).map返回一个数组数组,以提供控制台日志示例

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

添加concat

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

因此它将两级数组展平为单一级别,即

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

总而言之,该代码片段的作用是扁平化两级数组

filter(result => !!result)
只需&#34;过滤器&#34;输出任何&#34; falsey&#34;的数组元素。因为你有这个条件

if(childSnapshot.key == receiptID){

如果这是假的,那么undefined的结果将是map - 所有其他结果将是一个数组,甚至空数组都是真的 - 这就是过滤完成的原因很经常!可能有更好的方法来完成所有这些,但除非你真的处理数百万件物品,否则过滤空结果并不是真正的问题

最终结果是一个平面数组,只有从

中的代码返回的Promises