跳过JavaScript多级承诺.then() [英] JavaScript multi-level promises skipped .then()
问题描述
我遇到了多层承诺的问题。我试图做的是首先得到某些类别下的收据项目清单,然后对于每个收据项目,我得到它的详细信息和收据ID,收到收据ID后,我搜索帐户ID。然后,我根据帐户ID获取帐户详细信息。这是我的代码:
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. Then, I get the account details based on account 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);
});
我设法打印出 console.log $的结果c $ c>以上。但是,当我试图在这里打印出承诺时:
I managed to print out the result from the console.log
above. 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.
任何想法?谢谢高级!
推荐答案
我会在几个小时内提供更详细的解释,我事先约定,这意味着我现在无法提供详细信息
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
简单解决方案的第一步是创建一个函数从firebase快照中创建一个数组,因此我们可以使用map / concat / filter等。
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
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)));
});
在评论中解释问题
[]。concat
用于将多个数组的内容添加到新数组,即
[].concat
used to add the content of multiple arrays to a new array, i.e
[].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)
在这种情况下 snapshotToArray( data。.map
返回一个数组数组,给出一个控制台日志示例
In this case snapshotToArray(data).map
returns an array of arrays, to give a console log example
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]
因此它将两级数组展平为单一级别,即
so it flattens a two level array to a single level, i.e.
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){
如果为false,那么地图的结果将是
- 所有其他结果都是一个数组,甚至空数组都是真的 - 这就是为什么过滤经常这样做的原因!可能有更好的方法来完成所有这些,但除非你要处理数百万项,否则过滤空结果就没有真正的问题 undefined
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! 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
这篇关于跳过JavaScript多级承诺.then()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!