等待JS函数执行完成获取响应 修复Firebase上传URL未就绪执行后续逻辑问题
问题根源
你写的uploadFile本身没有返回Promise,uploadTask.on()是基于事件回调的异步API,函数执行到监听绑定那步就会同步结束返回,你在循环里写的await uploadFile()根本等不到上传完成、拿到下载链接的流程走完,自然会出现后续逻辑提前跑、URL没收集全的问题。
修复方案
1. 改造uploadFile为Promise风格
把上传逻辑包进Promise,单张图上传成功拿到URL就resolve,报错就reject,这样await才能真正等待上传流程结束。不要在上传函数里直接修改外部传入的data对象,直接把拿到的URL返回即可,避免不可控的副作用:
const uploadFile = useCallback((file) => { if (!file) return Promise.reject(new Error('无效上传文件')); const storageRef = ref(storage, `/images/${file.name}`); const uploadTask = uploadBytesResumable(storageRef, file); return new Promise((resolve, reject) => { uploadTask.on( "state_changed", (snapshot) => { // 需要做上传进度条就在这里计算进度,不需要可以留空 }, (err) => { console.error('图片上传失败:', err); reject(err); }, async () => { try { const downloadUrl = await getDownloadURL(uploadTask.snapshot.ref); resolve(downloadUrl); } catch (err) { reject(err); } } ); }) }, []);
2. 调整提交逻辑,统一收集所有URL后再执行后续操作
等所有图片上传流程全部结束、拿到完整的URL数组之后,再组装数据上传到Firestore,同时修正原来的判断顺序问题,加上异常捕获和loading状态的统一处理:
const handleFormSubmit = useCallback( async (data) => { setLoading(true); try { let downloadedUrl = []; if (data?.image?.length) { // 并行上传所有图片,速度更快;需要顺序上传的话看下面的替代写法 downloadedUrl = await Promise.all( data.image.map(img => uploadFile(img)) ); // 顺序上传替代写法(单张传完再传下一张): // for (const img of data.image) { // const url = await uploadFile(img); // downloadedUrl.push(url); // } } if (!downloadedUrl.length) { dispatch(handleAlertState({ message: "Error Occured!!!" })); router.push("/services"); return; } const submitData = { ...data, downloadedUrl }; await uploadDataToFirestore(submitData); router.push("/"); } catch (err) { console.error('提交失败:', err); dispatch(handleAlertState({ message: "Error Occured!!!" })); router.push("/services"); } finally { // 不管成功失败都关闭loading状态 setLoading(false); } }, [dispatch, router, uploadDataToFirestore, uploadFile] );
注意点
- 用
Promise.all做并行上传的话,只要有一张图上传失败就会直接进入catch分支,适合要求所有图片都必须上传成功的场景 - 原来在回调函数里直接push外部数组的写法依赖引用修改,异步时序不可控,改成等所有异步任务返回结果后统一组装数据的写法,能彻底避免URL收集不全的问题
- 原来的逻辑里
uploadDataToFirestore没有加await,也可能导致路由跳转时firestore上传还没完成,改造后加了await保证流程顺序正确
内容的提问来源于stack exchange,提问作者Chandler Bing
相关产品推荐
相关产品推荐

