Firebase getDownloadUrl获取URL推入数组显示为空但控制台存在数据
问题根因
「打印数组显示为空、展开控制台详情能看到数据」是两类问题叠加导致的:
- 控制台对数组、对象这类引用类型值采用懒加载读取逻辑:执行
console.log时仅保存值的内存引用,不会立刻序列化输出内容,手动展开控制台详情时才会读取当前内存中的最新值。也就是说执行打印语句的瞬间数组确实是空的,后续异步逻辑执行完向数组push数据后,展开看到的是更新后的状态。 - 代码异步时序逻辑存在三个明显错误:
onSnapshot是Firestore的实时事件监听回调,本身不会阻塞外层同步/异步代码执行,外层走到打印逻辑时,监听回调大概率还未触发,更不可能执行回调内部的异步URL请求逻辑。forEach方法本身不返回Promise,循环体内写async/await不会等待所有异步请求执行完成再走后续逻辑。Promise.resolve(response)只是将当前状态下的空数组包装为已决议的Promise,完全无法等待后续数据push的时机。
修复后代码
const getPostUrl = async (item) => { // 修正原代码问题:doc快照取数据需调用data()方法,getDownloadURL为官方标准驼峰命名 const url = await storage().ref(item.data()?.postName).getDownloadURL(); return { ...item.data(), URL: url }; }; const getUrls = () => { PostCollection.doc(UserInfo.uid) .collection("post") .onSnapshot(async (documentSnapshot) => { // 用map生成所有请求的Promise数组,通过Promise.all等待全部请求完成 const response = await Promise.all( documentSnapshot.docs.map(item => getPostUrl(item)) ); // 所有数据就绪后再执行后续操作:打印、更新状态等 console.log(response, "RESPONSE========>"); // setPosts(response) }); };
补充说明:如果不需要实时监听帖子数据变动,可将
onSnapshot替换为get()做一次性数据拉取,减少不必要的性能消耗。使用onSnapshot时需要在组件卸载阶段调用其返回的取消监听函数,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Pankaj Khati
相关产品推荐
相关产品推荐

