监听异步上传任务处理加载状态异常问题排查
问题解决:Firebase图片上传时Loading状态异常及报错处理
问题根源
- Loading提前关闭:
storeImage是async函数,但内部上传逻辑用的是回调监听,函数执行到uploadTask.on后就直接返回了,组件里的await会立刻结束,导致setLoading(false)提前执行,此时上传和Firestore写入还没完成。 - 加await报错:
uploadBytesResumable不返回Promise,它直接返回上传任务对象,给它加await后会得到undefined,调用uploadTask.on自然会报"undefined is not a function"的错误。
修改后的代码
1. 修复storeImage函数
将整个上传流程包裹在Promise中,确保外部await能等待所有异步操作完成:
export async function storeImage(uri: string, description: string) { // 返回Promise,让外部await等待整个流程结束 return new Promise(async (resolve, reject) => { const reference = ref(storage, `posts/${auth.currentUser!.uid}/${uuid.v4()}`); const blob: any = await new Promise((resolveBlob, rejectBlob) => { const xhr = new XMLHttpRequest(); xhr.onload = function () { resolveBlob(xhr.response); }; xhr.onerror = function (e) { console.log(e); rejectBlob(new TypeError('Network request failed')); }; xhr.responseType = 'blob'; xhr.open('GET', uri, true); xhr.send(null); }); // 不要给uploadBytesResumable加await const uploadTask = uploadBytesResumable(reference, blob); uploadTask.on( 'state_changed', (snapshot: any) => { const progress = snapshot.bytesTransferred / snapshot.totalBytes; console.log('Upload is ' + progress + '% done'); switch (snapshot.state) { case 'paused': break; case 'running': console.log('Upload is running'); break; } }, (error: any) => { console.log('Storage error', error); blob.close(); // 上传失败,reject Promise reject(error); }, async () => { try { // 等待下载链接获取和Firestore写入完成 const downloadURL = await getDownloadURL(uploadTask.snapshot.ref); console.log('File available at', downloadURL); await addImageReferenceToFirestore({ url: downloadURL, description }); blob.close(); // 所有操作完成,resolve Promise resolve(downloadURL); } catch (err) { console.log('后续操作失败', err); blob.close(); reject(err); } } ); }); }
2. 修复组件中的createPost函数
用try/catch/finally确保无论成功失败,Loading都会关闭:
async function createPost() { setLoading(true); try { await storeImage(rest.route.params.images[0], description); console.log('done'); // 这里可以加上传成功后的逻辑,比如跳转页面 } catch (err) { console.log('发布失败', err); // 这里可以加错误提示,比如Toast弹窗 } finally { // 不管成功失败,都关闭Loading setLoading(false); } }
关键修改点说明
storeImage返回Promise,将上传、获取下载链接、写入Firestore的全流程纳入Promise的resolve/reject逻辑,确保外部await能等待所有操作完成。- 上传完成回调中使用
async/await等待后续异步操作,避免只完成上传就结束流程。 - 组件中用
finally块关闭Loading,避免异常情况下Loading一直显示。 - 移除
uploadBytesResumable前的await,因为它不返回Promise,不需要等待。
内容的提问来源于stack exchange,提问作者Nilton Schumacher F
相关产品推荐
相关产品推荐

