JavaScript承诺绕过解决方案并继续.then()

时间:2017-08-01 13:50:04

标签: 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 => {
                //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);
}   
});

我设法使用&#39;内部承诺&#39;打印出console.log中的数据。但是,当我尝试从.then()打印出来时,没有任何显示。

现在的问题是,在我解决诺言之前,它实际上是先运行了.then()。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我从未使用过Firebase,但我确实知道承诺。 检查此示例链接承诺,请注意产生链接的return语句。

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

答案 1 :(得分:0)

这不是承诺如何运作,很少需要嵌套它们。如果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); }, []));

现在您有一个包含值数组的结果promise。您可以在其上调用then并对其进行迭代:

result.then(arr => arr.forEach(x => console.log(x.branchName)));