使用ConcatMap结合CombineLatest时请求次数超出预期问题排查
问题:带关联ID的顺序文件上传逻辑问题
我有一个NgRx Action/Effect,负责接收FileList并将文件依次上传到服务器。第一个文件上传完成后会生成一个ID,后续文件上传时需要传入这个ID,让后端建立关联关系。我用Component Store维护状态,里面包含初始值为null的ID和文件列表。
现在的问题是:第一个文件上传后更新Store中的ID时,用来保证顺序的concatMap还在处理所有文件,直到全部上传完成才会携带新ID生成新流,导致产生过多HTTP请求,而且后续文件都没用到第一个文件生成的ID。我不确定怎么在concatMap发起请求时获取Store中ID的最新值,猜测是combineLatest的位置不对。
原始尝试代码
readonly uploadFiles = this.effect((files: Observable<FileList>) => { return combineLatest([ files.pipe( mergeMap(list => Array.from(list).map(i => ({file: i, length: list.length})) ) ), // 存储第一个文件上传后生成的ID的Selector this.uploadId$, ]).pipe( concatMap(([tuple, uploadId], index) => this._dataSvc.upload(tuple.file, index, tuple.length, uploadId.ID).pipe( tap({ next: (event) => { switch (event.type) { case HttpEventType.UploadProgress: this.uploadProgress([ Math.round((event.loaded / event.total) * 100), index ]); break; case HttpEventType.Response: if(uploadId.ID === null) { // 调用Reducer更新当前上传批次的ID this.setUploadId(event.body.ID); } } }, }), catchError(() => EMPTY) // 暂时忽略错误 ) ) ) });
根据@maxime1992建议修改后的代码
readonly uploadFiles = this.effect((files$: Observable<FileList>) => { return files$.pipe( concatMap((files) => of({ ID: null, }).pipe( expand((ids, index) =>{ const idx = index/5; return files.length === idx || index % 5 !== 0 ? EMPTY : this._dataSvc.upload(files[idx], idx, files.length, ids.ID).pipe( tap({ next: (event) => { switch (event.type) { case HttpEventType.UploadProgress: this.uploadProgress([ Math.round((event.loaded / event.total) * 100), idx ]); break; case HttpEventType.Response: this.uploadCompleted(idx); } }, }), map((event, index) => event.type === HttpEventType.Response ? ({ ID: event.body.ID }) : ({ ID: null })), catchError(() => EMPTY) // 暂时忽略错误 ) }) ) ) );
内容的提问来源于Stack Exchange,提问作者Luis Lavieri
相关产品推荐
相关产品推荐

