[英]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.