我在JavaScript中承诺存在一些问题。所以我想要做的是我想从firebase中检索,然后将所有返回的结果存储到数组中。之后,我将对阵列执行一些排序。这是我的代码:
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);
});
});
使用这组代码,从promise中的第一个console.log
开始,我设法在我的控制台中获取这些代码:
有了这些,这意味着我的firebase检索没有任何问题。之后,我想将它们中的每一个存储到数组中,这就是它的一部分:
datasetarr.push({type: subtype, quantity: quantity});
完成所有事情后我解决了承诺,当承诺完成后,我打印出数组中的项目。但是,.then()
内的for循环中没有打印出任何内容。有什么想法吗?
答案 0 :(得分:1)
正如已经提到的:你的承诺太早解决了。
在解析包装Promise之前,您可以使用Promise.all等待所有承诺解决。我把一个简单的例子放在一起,但由于缺少firebase数据库,我只使用返回Promises的函数:https://jsfiddle.net/57b0gkLt/
根据firebase documentation,query.once('value')
会返回一个承诺,所以这应该有效。
编辑:喜欢这个
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);
}
});
答案 1 :(得分:1)
您正在正确处理检索初始数据集的第一次async
调用,但未处理.forEach
循环调用的后续调用。
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-around
可以做的是将forEach.async
调用包装到Promise
对象中,然后使用Promise.all([list_of_promises])
触发一组promises以确保每一个在主要承诺resolving
之前返回单个呼叫。
伪码:
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); });
});
});
答案 2 :(得分: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)
})
})