You need to enable JavaScript to run this app. 带进度监听的Firebase多图批量上传,提交过早致URL数组为空
优惠活动
大模型
产品
解决方案
定价
更多

带进度监听的Firebase多图批量上传,提交过早致URL数组为空

Firebase 批量图片上传导致提交时URL数组为空的修复

问题根因

时序错位的核心原因来自两点:

  • uploadMedia方法的返回值不符合Promise的等期待:storageRef.on()是用来注册状态监听的方法,返回值是取消监听的函数,根本不是“等上传全流程完成才resolve”的Promise。外层await this.uploadMedia()在监听注册完成后就立刻返回,完全不等后续的上传、获取下载链接的异步流程。
  • 依赖往this.firebaseImageUrls全局数组push值的副作用传参,在并行上传场景下,回调执行时机完全不可控,哪怕等上传完成,也可能出现submitPost执行时回调还没跑完、数组为空的情况。

具体修复步骤

1. 重写uploadMedia方法,返回全链路完成的Promise

不要用.on()的返回值当Promise,直接等上传任务本身落地后,把下载链接作为返回值传出来,进度监听保留但不阻塞主流程:

async uploadMedia(mediaFile: string): Promise<string> {
  const extension = mediaFile.split('.').pop()?.toLowerCase() || 'png';
  // 拼接时间戳降低文件名碰撞概率
  const mediaFileName = `${Date.now()}_${Math.round(Math.random()*100000000000)}.${extension}`;
  this.uploadProgress = 0;
  const response = await fetch(mediaFile);
  const blob = await response.blob();
  const uploadTask = storage.ref(mediaFileName).put(blob);

  // 单独注册进度监听,只用来同步进度UI,不影响主Promise的时序
  uploadTask.on(
    'state_changed',
    snapshot => {
      this.uploadProgress = snapshot.bytesTransferred / snapshot.totalBytes;
    },
    error => {
      this.error = error.message;
      this.submitting = false;
      this.uploadingMedia = false;
      // 错误直接抛出,让Promise.all能捕获到异常中断流程
      throw error;
    }
  );

  // 等待上传任务完全写入云端
  const uploadSnapshot = await uploadTask;
  // 拿取下载链接后直接返回,不依赖修改全局变量存值
  return await uploadSnapshot.ref.getDownloadURL();
}

2. 调整上传调用逻辑,从返回值收集URL

取消靠异步回调往全局数组push值的写法,等所有上传任务全跑完后,再统一分类赋值给全局URL数组,最后执行提交:

// 并行跑所有上传任务,拿到全量URL后再做分类
const allUploadedUrls = await Promise.all(
  this.props.store.selectedImagesArray.map(async (file: string) => {
    const url = await this.uploadMedia(file);
    const extension = file.split('.').pop()?.toLowerCase() || '';
    return { url, isImage: ['png', 'jpg', 'jpeg', 'webp'].includes(extension) };
  })
);

// 所有Promise都resolve完成后,再统一拆分图和视频的URL
this.firebaseImageUrls = allUploadedUrls.filter(item => item.isImage).map(item => item.url);
this.firebaseVideoUrls = allUploadedUrls.filter(item => !item.isImage).map(item => item.url);

// 这时候URL数组一定是完整的,再执行提交
this.submitPost();

排查补充提示

  • 原来的错误分支里只写了return,没有把异常向上抛出,会导致Promise.all误以为上传已经成功,哪怕中途报错也会继续执行submitPost,需要把错误正常抛出交给全局异常捕获处理。
  • 批量并行上传不要一次性放开太多并发,建议控制在3-5个同时上传,避免触发Firebase Storage的上传限流,可以简单加个并发队列做限流。
  • 原来纯靠随机数生成文件名有概率碰撞,会导致文件互相覆盖,拼接时间戳到文件名里能大幅降低重名概率。

内容的提问来源于stack exchange,提问作者frankied003

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.04 23:15:03