2017-07-31 11 views
2

私はJavaScriptの約束事に問題がありました。だから、私がやっていることは、firebaseから取り出して、返されたすべての結果を配列に格納したいということです。その後、配列のソートを行います。ここに私のコードは次のとおりです。JavaScriptの約束が解決しなかった

let promise = new Promise((resolve, reject) => { 
    var query = firebase.database().ref(''); 
     query.once('value', data => { 
      data.forEach(subtypeSnapshot => { 
       var itemData = ; 

       var query = firebase.database().ref('').child(itemKey); 
       query.once('value', data => { 
        var itemDetail = ; 
        datasetarr.push(); 
       }); 
      }); 
      resolve(datasetarr); 
     });    
    }); 

コードのこのセットでは、約束内の最初のconsole.logから、私は私のコンソールでこれらを得ることができた。これらにより

、それは私は何も問題がないことを意味しますfirebase retrieval。 Afterwhichは、私は、配列にそれらのそれぞれを保存したい、これは一部です:

すべてを行い、約束が行われたときに、私は、約束を解決
datasetarr.push({type: subtype, quantity: quantity}); 

した後、私は、配列内の項目をプリントアウト。しかし、.then()の中のforループで何も出力されません。何か案は?

+0

'解決(datasetarr);' '任意datasetarr.push({タイプ数量:サブタイプ、数量})の前に呼び出され、'実行され、なぜなら非同期コードは非同期です –

答えて

1

すでに述べたように、あなたの約束は早すぎると解決されます。

ラッププロミスを解決する前に、Promise.allを使用してすべての約束が解決するのを待つことができます。約束を返しquery.once('value')firebase documentationによると、https://jsfiddle.net/57b0gkLt/

、これは動作するはずです:私は理由firebaseデータベースの不足のため、しかし、一緒に簡単な例を入れて、私は約束を返す関数を使用します。

EDIT:初期正しく処理されたデータの集合ではなく.forEachループによって呼び出された以降のものを取得するため、この

var datasetarr = []; 
let promiseItemDataList = new Promise((resolve, reject) => { 
var query = firebase.database().ref('receiptItemIDsByCategory').child(category); 
    query.once('value', data => { 
     var promises = []; // NEW LINE 

     data.forEach(subtypeSnapshot => { 
      var itemData = subtypeSnapshot.val(); 
      var itemKey = subtypeSnapshot.key; 

      var query = firebase.database().ref('receiptItems').child(itemKey); 
      var promise = query.once('value'); // NEW LINE 
      promises.push(promise); // NEW LINE 

      promise.then(data => { // .then instead of a callback 
       var itemDetail = data.val(); 
       var subtype = itemDetail.type; 
       var quantity = itemDetail.quantity; 
       console.log('inside promise ' + subtype + ' ' + quantity); 
       datasetarr.push({type: subtype, quantity: quantity}); 
      }); 
     }); 

     Promise.all(promises).then(() => resolve(datasetarr)); // NEW LINE 
    });    
}); 

promiseItemDataList.then((arr) => { 
    for(var i = 0; i < arr.length; i++){ 
     console.log('outside promise ' + arr[i].type + ' ' + arr[i].quantity); 
    } 
}); 
+0

申し訳ありませんが、私はコードを読んで混乱しました。では、私のケースに適用できるように変更するにはどうすればいいですか? getQuery()内のコードをitemKeyを取得する部分に変更することによって、 – hyperfkcb

+0

@DeniseTan編集済みの記事を参照してください。 firebaseのドキュメントを理解しているので、Promiseを返す '.once( 'value'、callback)'や 'onon( 'value')'を使うことができます(私は間違いないと思います。 。 – SVSchmidt

+0

申し訳ありませんが、私が間違っている場合は私を修正します。私はそれがどのように動作するのか理解しようとしています。だから、あなたがしたことは、最初のクエリのすべての約束のために別の配列を宣言することです。次に、.thenを使用して2番目のクエリでチェーンし、データをdatasetarrにプッシュします。その後、forEachとループに戻ります。 Promise.allを使用してすべての約束が完了したら、そこで確認してから、データセットを解決します。私は正しい? – hyperfkcb

1

あなたの最初のasync呼び出しのように。

query.once('value', data => { 
    var itemDetail = data.val(); 
    var subtype = itemDetail.type; 
    var quantity = itemDetail.quantity; 
    console.log('inside promise ' + subtype + ' ' + quantity); 
    datasetarr.push({type: subtype, quantity: quantity}); 
}); 

トラブルは、他の非同期呼び出しが返された前にresolving約束をしているです。

query.onceの処理方法がわかりませんcallbackです。それは約束をしているのではなく、伝統的なcallback functionのように見えません。

work-aroundPromiseオブジェクトにforEach.asyncの呼び出しをラップして、すべての単一の呼び出しはresolvingメイン約束する前に返されたことを確認するためにPromise.all([list_of_promises])を使用して約束のコレクションを発射することであるとして、あなたは何ができますか。

擬似コード:

var datasetarr = []; 
let promiseItemDataList = new Promise((resolve, reject) => { 
    var query = firebase.database().ref('receiptItemIDsByCategory').child(category); 
    query.once('value', data => { 

     // Collect a list of promises for the sub item async calls 
     var get_data_promises = []; 
     data.forEach(subtypeSnapshot => { 
      get_data_promises.push(new Promise(function(resolve) { 
       var itemData = subtypeSnapshot.val(); 
       var itemKey = subtypeSnapshot.key; 
       var query = firebase.database().ref('receiptItems').child(itemKey); 

       query.once('value', data => { 
        var itemDetail = data.val(); 
        var subtype = itemDetail.type; 
        var quantity = itemDetail.quantity; 
        console.log('inside promise ' + subtype + ' ' + quantity); 
        datasetarr.push({type: subtype, quantity: quantity}); 
        resolve("Done"); 
       }); 
     })) 

     // Fire them all - Once done resolve the main promise. 
     Promise.all(get_data_promises).done(function() { resolve(datasetarr); }); 
    }); 
}); 
+0

ありがとうございます! – hyperfkcb

1
var query = firebase.database().ref('receiptItemIDsByCategory').child(category); 

query.once('value') 
.then((data) => { 
    promises =[] 
    data.forEach(subtypeSnapshot => { 
     var itemData = subtypeSnapshot.val(); 
     var itemKey = subtypeSnapshot.key; 

     var query = firebase.database().ref('receiptItems').child(itemKey); 
     p = query.once('value', data => { 
        var itemDetail = data.val(); 
        var subtype = itemDetail.type; 
        var quantity = itemDetail.quantity; 
        console.log('inside promise ' + subtype + ' ' + quantity); 
       }); 
     promises.push(p) 
    }) 
    return promises 
}) 
.then ((arrayofpromises) => { 
    Promise.all(arrayofpromises) 
    .then((results)=>{ 
     console.log(results) 
    }) 
}) 
+0

しかし、data.mapは関数ではないというエラーメッセージが表示されます。 – hyperfkcb

+0

ああ、firebaseは 'forEach'を持っていますが、マップはありません。たぶん編集が近い@DeniseTan –

+0

ありがとうございます!!! – hyperfkcb

関連する問題