You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

监听异步上传任务处理加载状态异常问题排查

问题解决:Firebase图片上传时Loading状态异常及报错处理

问题根源

  1. Loading提前关闭:storeImage是async函数,但内部上传逻辑用的是回调监听,函数执行到uploadTask.on后就直接返回了,组件里的await会立刻结束,导致setLoading(false)提前执行,此时上传和Firestore写入还没完成。
  2. 加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:45:39