我正在尝试使用他们的Firebase API以递归方式获取黑客新闻故事的所有评论。故事具有kids
属性,该属性是表示注释的ID数组。每个注释都可以有自己的kids
属性,指向其子注释,依此类推。我想创建一个整个注释树的数组,看起来像:
[{
'title': 'comment 1',
'replies': [{
'title': 'comment 1.1'
}, {
'title': 'comment 1.2'
'replies': [{
'title': 'comment 1.2.1'
}]
}]
}]
我以为我可以使用以下功能执行此操作:
function getItem(id) {
return api
.child(`item/${id}`)
.once('value')
.then((snapshot) => { // this is a Firebase Promise
let val = snapshot.val()
if (val.kids) {
val.replies = val.kids.map((id) => getItem(id))
}
return val
})
}
然后在使用以下内容获取整个评论树后收到通知:
getItem(storyId)
.then(story => {
// The story and all of its comments should now be loaded
console.log(story)
})
最终发生的事情是Promise.all().then()
在第一级评论承诺解决后触发(这是有道理的,因为所有commentPromises
已经解决了。)但是,我想知道所有嵌套承诺已经解决。我怎么能这样做?
答案 0 :(得分:7)
在其他答案中不需要包装器承诺;这就是“explicit promise constructor anti-pattern”。精简一点,您可以执行以下操作:
function getItem(id) {
return api
.child(`item/${id}`)
.once('value')
.then(snapshot => {
const val = snapshot.val();
return Promise.all((val.kids || []).map(getItem))
.then(kidsVals => {
val.replies = kidsVals;
return val;
});
);
});
}
也不需要任何明确的拒绝处理。拒绝会自然地传播到顶层(假设这是你想要的)。
答案 1 :(得分:3)
IMP:请参阅azaburo的回答。它比我的要好得多。
======
我认为这应该有效:
function getItem(id) {
return new Promise(function(resolve, reject) {
api
.child(`item/${id}`)
.once('value')
.then((snapshot) => { // this is a Firebase Promise
let val = snapshot.val()
if (val.kids) {
let replies = val.kids.map((id) => getItem(id))
Promise.all(replies).then(replies => {
val.replies = replies // <<<<<< try this
resolve(val) // we want to resolve val, not val.replies
}, err =>{
reject(err)
})
} else {
resolve(val)
}
})
.catch((err) => { // if there was some error invoking api call we need to reject our promise
reject(err);
})
}
}
修改强>
在val.replies
then