我的应用程序是使用React和Firebase构建的。该应用程序中有一项功能,允许用户创建播放列表,并用目录中的曲目填充它们。播放列表具有一个称为“曲目”的子集合,用于存储曲目ID和其他一些信息。查看播放列表时,我想遍历曲目并将它们交叉引用(如SQL中的联接)到Tracks集合以填充视图。
// Looks something like this before the return...
// Attempting to write an async/await function
async function getTrackDocument(trackId) {
const track = await firestore
.collection("tracks")
.doc(trackId)
.get();
return track;
}
useEffect(() => {
const playlistRef = firestore.doc(`playlists/${playlistId}`);
const playlistTracksRef = firestore.collection(
`playlists/${playlistId}/tracks`
);
playlistRef.get().then(doc => {
if (doc.exists) {
const unsubscribe = playlistTracksRef.onSnapshot(snapshot => {
// Snapshot of playlist tracks
const playlistTracks = snapshot.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Getting the track document
trackRef: getTrackDocument(doc.id).then(doc => {
return doc.data();
})
};
});
setTracks(playlistTracks);
});
return () => unsubscribe();
}
});
});
我要交叉引用播放列表轨道ID到“轨道”集合的部分:
trackRef: getTrackDocument(doc.id).then(doc => {
return doc.data();
})
我希望能为我提供所需的曲目信息。该部分在控制台中返回一个Promise对象:
trackRef: Promise
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Object
__proto__: Object
[[PromiseValue]]
具有所有值,但似乎无法到达可以使用这些值的位置。我可以将doc.data()
登录到控制台,它向我显示了最终需要的值。有没有办法以代码编写的方式内联地返回这些值?我尝试了不同的方式来编写异步/等待功能,并且还尝试返回Promise.resolve(data)
,始终保持相同的结果。
我最希望达到的行为是通过创建一个函数,在该函数中可以抓取Track并将其推入状态的tracks数组中,例如:
// @param arrayOfTrackIDs -- just track IDs from the playlist
function getTracksThenPopulateArray(arrayOfTrackIDs) {
arrayOfTrackIDs.forEach(trackID => {
firestoreTracks.doc(trackID).get().then(doc => setTracks(tracks => [...tracks, track]));
}
}
但是,这并不理想,因为如果删除或添加了轨道,我无法合并.onSnapshot()来更新视图。
类似于用户Gazihan的建议,我使用了他的async / await Promise.all()并为内部文档添加了async / await Promise.resolve(),并且有效:
const unsubscribe = playlistTracksRef.onSnapshot(async snapshot => {
const playlistTracks = await Promise.all(
snapshot.docs.map(async doc => {
return {
id: doc.id,
...doc.data(),
trackRef: await Promise.resolve(
getTrackDocument(doc.id).then(doc => {
return doc.data();
})
)
};
})
);
setTracks(playlistTracks);
});
答案 0 :(得分:1)
map()
已同步。使用map()
只能获得Promise
实例的列表。您必须等待它们中的每个使其成为具有实际值的列表。 Promesi.all()
做到了。
这是固定代码:
const playlistTracks = await Promise.all(snapshot.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Getting the track document
trackRef: getTrackDocument(doc.id).then(doc => {
return doc.data();
})
};
}));
但是,要能够在await
之前使用Promise.all()
,您需要处于异步函数中。这是一个尝试,应该可以工作:
const unsubscribe = playlistTracksRef.onSnapshot(async snapshot => {
// Snapshot of playlist tracks
const playlistTracks = await Promise.all(snapshot.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Getting the track document
trackRef: getTrackDocument(doc.id).then(doc => {
return doc.data();
})
};
}));
setTracks(playlistTracks);
});