如何为Observable添加属性,实现Firebase上传进度与下载URL同时返回
实现方案
核心思路
- 自定义联合类型作为Observable的返回值,区分「进度更新」和「上传完成返回URL」两类事件
- 合并上传进度流、获取下载URL流,避免内部独立订阅导致的数据流割裂
- 所有输出统一通过返回的Observable下发,调用方统一处理即可
第一步:修改文件上传服务代码
先定义返回事件类型,再重构pushFileToStorage方法,移除内部的独立subscribe调用,用RxJS操作符组合数据流:
import { from, map, concatWith } from 'rxjs'; // 可直接放在服务类上方或者公共类型文件中 type UploadEvent = | { type: 'progress', percentage: number } | { type: 'complete', downloadUrl: string }; pushFileToStorage(fileUpload: FileUpload): Observable<UploadEvent> { const filePath = `${this.basePath}/${fileUpload.file.name}`; const storageRef = this.storage.ref(filePath); const uploadTask = this.storage.upload(filePath, fileUpload.file); return uploadTask.percentageChanges().pipe( // 把进度值映射为进度事件 map(percentage => ({ type: 'progress', percentage: Math.round(percentage ?? 0) } as UploadEvent)), // 进度流完成(即上传完成)后,拼接获取下载URL的流 concatWith( from(storageRef.getDownloadURL()).pipe( map(url => { // 赋值给fileUpload对象,兼容原有逻辑 fileUpload.url = url; fileUpload.name = fileUpload.file.name; return { type: 'complete', downloadUrl: url } as UploadEvent; }) ) ) ); }
第二步:修改服务调用逻辑
在订阅回调中判断事件类型,分别处理进度更新和上传完成逻辑:
this._firestoreStorageService .pushFileToStorage(this.currentFileUpload) .subscribe({ next: (event) => { if (event.type === 'progress') { this.percentage = event.percentage; } else if (event.type === 'complete') { const downloadUrl = event.downloadUrl; // 直接用下载URL更新用户资料即可 } }, error: (error) => { console.log('上传失败:', error); } });
注意事项
- 不需要再单独判断进度是否到100%,
complete事件触发时就代表上传已经完成、URL已经获取成功 - 原有内部订阅被移除,所有生命周期跟随调用方的订阅,避免内存泄漏风险
- 如果使用RxJS6及以下版本,可以把
concatWith替换为concat操作符调整流的拼接逻辑
内容的提问来源于stack exchange,提问作者ccocker
相关产品推荐
相关产品推荐

