问题
I am trying to understand rxjs (6) and how I should call conditionally make a second http post.
My scenario is that:
- I am/have uploaded a file.
- I get an object identifying the current progress and a filename.
- If the current progress is 100 I want to make the second http post and on success of that second call return the progress and the filename
- If the current progress is less than 100 simply return the progress and filename
My class
export class BasePortalDetailsManagerService {
updateCertificate(file: File): Observable<IUploadProgress> {
return this._azureBlobStorage
.uploadCertificateToBlobStorage2(file, this.portalKey)
.pipe(
map(progress => this.mapProgress2(progress))
);
}
private mapProgress2(fileProgress: FileProgress): IUploadProgress {
if (fileProgress.Progress === 100) {
console.log('I can do something here but there must be a better way');
} else {
return {
filename: fileProgress.FilePath,
progress: fileProgress.Progress
};
}
}
}
I have been watching and reading various stuff and the only that seems to happen is, it convinces me my way is wrong. I cant seem to get my head round the various tutorials.
various links I've followed
rxjs quick start
cory rylan
rxjs where is the if/else
回答1:
Instead of map
use concatMap
and depending on progress
return this original object wrapped in an Observable with of(progress)
or return another Observable that makes the second request and map its result to progress
:
this._azureBlobStorage.uploadCertificateToBlobStorage2(file, this.portalKey).pipe(
concatMap(progress => progress.Progress === 100
? this.mapProgress2(progress).pipe(
map(filename => ({ // This could go inside `mapProgress2` as well
filename: progress.FilePath,
progress: progress.Progress
})),
)
: of(progress)
),
);
回答2:
I was able to resolve my issue thanks to @martin pointing me in the right direction.
I change mapProgress2()
return type to be Observable<IUploadProgress>
then use flatMap to flatten the inner observable.
My knowledge of rxjs is very limited but I believe for scenario flatMap
, switchMap
or concatMap
would suffice. @martin suggested concatMap
and after reading the docs I agree.
From The RXJS docs
flatMap: flatMap is an alias for mergeMap!
mergeMap: If you would like more than one inner subscription to be maintained, try mergeMap
switchMap: If only one inner subscription should be active at a time, try switchMap
concatMap: If the order of emission and subscription of inner observables is important, try concatMap
updateCertificate(file: File): Observable<IUploadProgress> {
return this._azureBlobStorage
.uploadCertificateToBlobStorage2(file, this.portalKey)
.pipe(
flatMap(progress => this.mapProgress2(progress))
);
}
private mapProgress2(fileProgress: IUploadProgress): Observable<IUploadProgress> {
if (fileProgress.progress === 100) {
return this._httpClient.post(this._portalDetails + 'certificatePath', JSON.stringify(fileProgress.filename))
.pipe(map(res => fileProgress));
} else {
return Observable.create(function(observer) {
observer.next(fileProgress);
observer.complete();
});
}
}
来源:https://stackoverflow.com/questions/55072397/rxjs-conditionally-make-a-second-http-call