Firebase图片上传存Firestore时await无作用报错解决方案
问题根源
你遇到的问题来自两个核心错误:
uploadImages函数没有返回Promise:你在上传完成回调里写的return downloadURL只是回调函数的内部返回值,不会作为uploadImages的执行结果返回给外部调用方,所以不管上传成不成功,外部拿到的都是默认返回值undefined- 异步时序完全错误:就算函数返回Promise,你原来的写法既没有等待单个上传任务完成,也没有等待所有文件全部上传拿到URL,就直接执行了Firestore写入操作;另外React Hook Form的
setValue不会同步更新当前onSubmit闭包里拿到的formData对象,就算你调用setValue改了值,后面拿原formData写入还是旧的文件列表,不是URL数组。
修复步骤
第一步:改造uploadImages函数,让它返回Promise
把整个上传逻辑用Promise包裹,上传成功拿到下载URL时触发resolve,上传出错时触发reject,改造后的代码如下:
import { getStorage, ref, uploadBytesResumable, getDownloadURL, } from 'firebase/storage'; const uploadImages = (file, fileName) => { // 对外返回Promise实例,外部才能用await等待结果 return new Promise((resolve, reject) => { const storage = getStorage(); const storageRef = ref(storage, `images/${fileName}`); const uploadTask = uploadBytesResumable(storageRef, file); uploadTask.on( 'state_changed', (snapshot) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log('Upload is ' + progress + '% done'); switch (snapshot.state) { case 'paused': console.log('Upload is paused'); break; case 'running': console.log('Upload is running'); break; } }, // 上传出错直接reject,让外层能捕获错误 (error) => { reject(error); }, // 上传完成后获取下载地址 () => { getDownloadURL(uploadTask.snapshot.ref) .then((downloadURL) => { console.log('File available at', downloadURL); // 拿到URL后resolve,外部就能接收到这个值 resolve(downloadURL); }) .catch(reject); } ); }) }; export default uploadImages;
第二步:修改onSubmit中的图片上传逻辑,等待所有上传完成再写入
这里要注意三个细节:
- 给
map的回调加上async关键字,内部才能正常使用await map执行后返回的是Promise数组,需要用Promise.all等待所有上传任务完成,才能拿到全部URL组成的数组- 拿到URL数组后直接修改要提交的
formData对应字段,不要依赖setValue的同步更新,避免闭包陷阱导致写入旧值
修改后的图片上传+写入部分代码:
// 上传图片逻辑 if (formData.imageUrls.length > 0) { // map回调加async,每个上传任务返回一个Promise const uploadPromises = Array.from(formData.imageUrls).map((file) => uploadImages(file, `${formData.userRef}-${file.name}`) ); // 等待所有图片上传完成,拿到最终的URL数组 const imageURLs = await Promise.all(uploadPromises); // 直接修改提交对象的字段,避免闭包导致值不生效 formData.imageUrls = imageURLs; // 如果需要同步更新表单视图可以保留这行,不影响后续写入 setValue('imageUrls', imageURLs); } // 所有数据准备完成后再写入Firestore await addDoc(collection(db, 'listings'), formData);
补充说明
- 之前收到的
'await' has no effect on the type of this expression警告,本质就是原uploadImages没有返回Promise,await等待一个普通值没有任何异步等待效果,改造完函数后这个警告会自动消失 - 如果需要处理单张图片上传失败不阻塞整体流程的场景,可以把
Promise.all换成Promise.allSettled,过滤掉上传失败的项即可
内容的提问来源于stack exchange,提问作者hitayco
相关产品推荐
相关产品推荐

