[英]How can I chain multiple dependent subscriptions using rxjs operators and transformations?
[英]How can I avoid multiple nested subscriptions using RxJS operators?
我正在使用Angular進行文件加密和上載類。 這些操作很多都是異步的,因此我編寫的方法返回RxJS Observables。
// 1.
private prepareUpload(file): Observable<T>;
// 2.
private encryptData(data, filekey): Observable<T>
// 3.
private uploadEncryptedData(formData, token, range): Observable<T>
// 4.
private completeUpload(updatedFilekey, token): Observable<T>
我想將此邏輯封裝在公共的upload(file)
方法中,最終使用了嵌套訂閱,並且可以使用,但我知道這是錯誤的,並且出於多種原因,RxJS中使用了反模式。 這是代碼的簡化版本:
public upload(file) {
const gen = this.indexGenerator(); // generator function
this.prepareUpload(file).subscribe(values => {
const [response, filekey, data] = values;
this.encryptData(data, filekey).subscribe(encryptedDataContainer => {
const formData = this.prepareEncDataUpload(encryptedDataContainer.data, file.name)
const range = this.getRange(file.size, gen.next().value);
this.uploadEncryptedData(formData, response.token, range).subscribe(() => {
if (range.isFinalPart) {
this.completeUpload(encryptedDataContainer.updatedFilekey, response.token).subscribe(console.log);
}
});
});
});
}
我無法使用多個RxJS運算符的組合來清除此代碼。 我的目標是避免嵌套訂閱,而是在工作流完成時從公共的upload()
方法返回單個Observable。
謝謝!
您可以使用mergeMap
和filter
運算符並鏈接您的調用。 您將需要創建一些函數級變量以在鏈接期間使用。
import { mergeMap, filter, catchError } from 'rxjs/operators`
public upload(file) {
const gen = this.indexGenerator(); // generator function
let range, token;
this.prepareUpload(file)
.pipe(
mergeMap((values) => {
const [response, filekey, data] = values;
token = response.token;
return this.encryptData(data, filekey);
}),
mergeMap(encryptedDataContainer => {
const formData = this.prepareEncDataUpload(encryptedDataContainer.data, file.name)
range = this.getRange(file.size, gen.next().value);
return this.uploadEncryptedData(formData, token, range);
}),
filter(() => !!range.isFinalPart),
mergeMap(() => {
return this.completeUpload(encryptedDataContainer.updatedFilekey, token);
})
catchError((error) => {
console.log(error);
// handle the error accordingly.
})
)
.subscribe(() => {
console.log('success');
});
}
您想要在訂閱之前使用管道。 管道允許您在流發出值之前對流中的值進行更改。 另外,使用mergeMap
展平訂閱鏈。 這里是概述。 這不能提供完整的解決方案-付給我的錢還不夠;)-但這足以為您指明正確的方向:
this.prepareUpload(file).pipe(
tap(values => console.log('hello1', values)),
map(values => [response, filekey, data]),
tap(values => console.log('hello2', values)),
mergeMap(() =>
// essential to catchError else an HTTP error response will disable this effect - if it uses HTTP - catchError essentially prevents the stream from erroring in which case it will never emit again
this.encryptData(data, filekey).pipe(
map(res => res), // do something with res here if you want
catchError(() => {
return of(null)
})
)
),
filter(res => !!res)
// more mergemap stuff here
).subscribe(values => {
console.log(values)
})
提示:使用tap運算符在流向下傳遞值時控制台.log值
PS:語法未選中,可能缺少逗號或方括號或2
PPS:管道中的函數都是RxJS運算符
您可以使用mergeMap rxjs運算符合並這些可觀察對象,並擺脫嵌套訂閱。
盡管有一個陷阱,但是請注意,由於mergeMap會同時維護多個活動的內部訂閱,因此有可能通過長期存在的內部訂閱造成內存泄漏。
作為參考和示例: https : //www.learnrxjs.io/operators/transformation/mergemap.html
我覺得你的鏈接觀測將做到這一點,你可以用flatMap(別名mergeMap)做到這一點,也許- https://stackoverflow.com/a/37777382/9176461和RxJS無極組成(傳遞數據)
就像我在評論中所說的那樣,類似以下的東西應該起作用(偽代碼):
public upload(file) {
const gen = this.indexGenerator(); // generator function
return Rx.Observable.just(file).pipe(
mergeMap(this.prepareUpload),
mergeMap(this.encryptData),
mergeMap(this.prepareEncDataUpload),
mergeMap(this.prepareEncDataUpload),
.... )
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.