为何forkJoin返回UploadTaskSnapshot而非Firebase存储下载URL?
解决Firebase Storage批量上传后获取下载URL数组的问题
我懂你的困扰——单独处理单个上传时能拿到正确的下载URL,但用forkJoin批量处理时,控制台输出的却是上传快照数组,完全不是你要的结果。这其实是因为你当前的Observable流输出的是上传过程中的快照,而finalize并不会改变流的输出值,它只是在流结束时执行额外逻辑而已。
问题根源
finalize操作符的作用是在Observable完成(不管是正常结束还是出错)时执行一段代码,但它不会修改Observable最终发出的值。所以你当前的每个Observable最终输出的还是snapshotChanges()的最后一个快照对象,forkJoin自然收集到的就是这些快照的数组了。
解决方案
要让每个Observable最终输出下载URL,我们需要在上传完成后,把流切换到获取下载URL的Observable。可以通过last()获取上传完成的最后一个快照,再用switchMap切换到getDownloadURL()的流:
修改你的startUpload方法中构建observableList的部分:
startUpload() { if (typeof this.fileList !== 'undefined' && this.fileList.length > 0) { const observableList = []; for (let i = 0; i < this.fileList.length; i++) { // The storage path const path = this.userModel.companyCode + `/${new Date().getTime()}_${this.fileList[i].name}`; // Totally optional metadata const customMetadata = { app: 'My AngularFire-powered PWA!' }; const fileRef = this.storage.ref(path); // The main task this.task = this.storage.upload(path, this.fileList[i], { customMetadata }); // 修改这里的Observable构建逻辑 const uploadAndGetUrl$ = this.task.snapshotChanges().pipe( last(), // 等待上传完成,取最后一个进度快照 switchMap(() => fileRef.getDownloadURL()) // 切换到获取下载URL的流 ); observableList.push(uploadAndGetUrl$); } forkJoin(observableList).subscribe(response => { console.log('所有下载URL:', response); // 现在这里会输出你想要的URL数组 }); } }
为什么这样有效?
last():确保我们等到上传任务完全结束(因为snapshotChanges()会发出多个进度快照,last()只取最后一个,也就是上传完成的那个)。switchMap(() => fileRef.getDownloadURL()):将当前流切换到获取下载URL的Observable,这样整个流的最终输出就是下载URL,forkJoin就能收集到所有任务的URL组成的数组了。
另外提一句:你之前单独处理时写的await fileRef.getDownloadURL().toPromise有个小笔误,应该是toPromise()(需要调用方法),不过用RxJS的操作符来处理流会更符合AngularFire的使用习惯,也更优雅。
内容的提问来源于stack exchange,提问作者wavrik
相关产品推荐
相关产品推荐

