JavaScript承诺绕过解析并继续执行.then()
我在嵌套承诺方面遇到了一些问题,这导致了忘记承诺的问题JavaScript承诺绕过解析并继续执行.then(),javascript,firebase,asynchronous,firebase-realtime-database,promise,Javascript,Firebase,Asynchronous,Firebase Realtime Database,Promise,我在嵌套承诺方面遇到了一些问题,这导致了忘记承诺的问题 let promiseList = new Promise((resolve, reject) => { //first query to retrieve from firebase query.once( 'value', data => { var promises = []; data.forEach(snapshot => {
let promiseList = new Promise((resolve, reject) => {
//first query to retrieve from firebase
query.once( 'value', data => {
var promises = [];
data.forEach(snapshot => {
//get item key
//second query based on item key
var promise = query.once('value');
promises.push(promise);
promise.then(data => {
var itemDetail = data.val();
var receiptID = itemDetail.receiptID;
// third query to find matching receiptID
var query = firebase.database().ref('receipts');
query.once('value', data => {
data.forEach(snapshot => {
snapshot.forEach(childSnapshot => {
if(childSnapshot.key == receiptID){
var branchDetail = childSnapshot.val().branch;
var branchName = branchDetail.branchName;
//console.log('inside promise ' + branchName);
datasetarr.push({branchName: branchName});
}
});
});
});
});
});
// wait till all promises are finished then resolve the result array
Promise.all(promises).then(() => resolve(datasetarr));
});
});
// print out array here
promiseList.then((arr) => {
for(var i = 0; i < arr.length; i++){
console.log(arr[i].branchName);
}
});
我设法用“inside promise”从console.log打印出数据。然而,当我试图从打印出来。然后,没有显示任何内容
现在的问题是它实际上运行了。然后在我解决承诺之前
有什么想法吗?我从未使用过Firebase,但我知道承诺。 检查此示例链接承诺,注意生成链接的返回语句
var outerPromise = query.once('value').then(data => {
// Promise array to group 2nd level promises and then do a Promise.all.
var promises = [];
// This will be the main output of the outerPromise.
// We will populate it asynchronously inside our 2nd level promises.
var datasetarr = [];
data.forEach(snapshot => {
// 2nd level promises, will be appended to the promises array.
// and will be enchained with the 3d level promise.
var promise = query.once('value').then(data => {
var itemDetail = data.val();
var receiptID = itemDetail.receiptID;
var query = firebase.database().ref('receipts');
// Third level promise. It's enchained by the return statement.
return query.once('value').then(data => {
data.forEach(snapshot => {
snapshot.forEach(childSnapshot => {
if(childSnapshot.key == receiptID){
var branchDetail = childSnapshot.val().branch;
var branchName = branchDetail.branchName;
//console.log('inside promise ' + branchName);
datasetarr.push({branchName: branchName});
}
});
});
});
});
promises.push(promise);
});
// We wait until 2nd (and third) level promises are ready
// and the return our desired output, the datasetarr
return Promise.all(promises).then(()=> datasetarr);
});
// Since it's all chained, the outerPromise will resolve once all promises are completed
// and we can get the output we supplied in the last chaining.
outerPromise.then((arr) => {
console.log(arr)
});
承诺不是这样起作用的,很少有人需要把它们嵌套起来。如果query.once已经返回了一个非常好的承诺,那么您需要将其打包:
let returnsPromise = value => new Promise(res => query.once(value, data => res(data));
再说一次,如果它已经返回了一个不必要的承诺,但我不是火箭筒。无论如何,现在你可以做这样的事情:
let result = returnsPromise('value')
// run secondary query based on item key
.then(data => Promise.all(data.map(item => returnsPromise(item.key)))
// now do stuff with those results
.then(data => {
return Promise.all(data.map(item => {
let receiptID = item.val().receiptID;
// Note that the same 'wrap if not already returning promise
// idea' is applicable here, but for illustration I'm just
// going to act like this returns a promise.
// Also note that while I've been rather down on nesting
// its more or less necessary here because you need to capture
// the receipt ID from the surrounding scope.
return firebase.database().ref('receipts')
.once('value')
.then(snapshot => {
return snapshot
.filter(x => x.key === receiptID)
.map(x => {
let branch = x.val().branch.branchName;
return {branch: branch};
});
});
}))
// Now we have an array of arrays of results but we want to
// remove the nesting.
.then(arrayOfArrays => arrayOfArrays.reduce((x,y) => { return x.concat(y); }, []));
现在您有了一个包含值数组的结果承诺。然后,您可以调用它并对其进行迭代:
result.then(arr => arr.forEach(x => console.log(x.branchName)));
为什么要筑巢?这完全没有必要。你有没有尝试过使用promises.pushpromise。然后呢?我想做的是首先得到一个收据项目的列表。然后,对于每个收据项目,我都会得到它的详细信息,比如receiptID。然后,我继续根据receiptID查找分支详细信息。有了这些,我就有了嵌套的承诺。我不知道如何真正分开them@CameloCatafarno你是说把它放在后面,然后呢?但我认为你应该先把它推到数组中?你把它推到数组中,然后在没有传递新承诺的情况下将它进一步链接到数组中。然后创建数组。两项中只有一项需要通过。此外,没有任何东西返回到。那么,它不会等待里面的东西完成。为什么?请解释一下,不,请告诉我。我也不确定另一个人。不管怎样,所有的答案都被否决了。@EmmaHannah,一个好的经验法则是不要筑巢:这是承诺应该解决的问题之一。请记住,正如莱昂纳多·查亚(Leonardo Chaia)所指出的,在a中返回一个值,然后返回该值的承诺。还请记住,您可以返回一个数组,然后在链的下一步中使用它。另一个好的经验法则是不要在链中的任何一个步骤中做太多,这会使测试和调试更加困难。@JaredSmith Cool非常感谢您的帮助!但是.map和.filter做什么呢?要将相关数据映射到一起并过滤不必要的数据?@EmmaHannah map接受一个函数并返回将其应用于数组中每个元素的结果。筛选器接受一个函数,并将该函数返回true的数组中的项保留为不起作用的.Nope。在console.log中仍然没有打印任何内容。then@EmmaHannah,检查编辑。顺便说一句,你应该读一些关于。谢谢它的作品!让我试着去理解它是如何工作的。所以基本上你创建了一个outerPromise来包装所有其他的承诺。然后,当您循环遍历每个itemKey时,您创建了一个承诺列表,以获取其详细信息和分支详细信息。之后,您将它们添加到promise数组中。等等,我想我基本上是在读代码。你介意详细解释一下吗?@LeonardoChaia嘿,很抱歉再次打扰你!但假设从第三级承诺开始,我需要获取receiptID并查询另一个account表。我怎样才能做到这一点?我可以从firebase声明一个要查询的新承诺,然后在返回三级承诺时将该承诺推送到承诺数组中吗?