RxJS 6 - Cancel / End a Pipe
使用新版本的RxJS 6,尤其是管道运算符。当前,使用管道获取API调用的结果,并将其传递给一系列其他任务。
一切正常,但在遇到问题时似乎无法找到取消或终止管道的方法。例如,我正在使用tap运算符检查该值是否为null。然后,我抛出一个错误,但是管道仍然似乎移至下一个任务,在本例中为concatmap。
因此,您如何过早结束或取消管道?预先感谢。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | getData(id: String): Observable { return this.http.get(`${this.baseUrl}/path/${id}`).pipe( tap(evt => { if (evt == null) { return throwError(new Error("No data found...")); } }), concatMap( evt => <Observable>( this.http.get( `${this.baseUrl}/path/relatedby/${evt.child_id}` ).map(res =>( {"response1":evt,"response2":res}) ) ) ), retry(3), catchError(this.handleError("getData", [])) );} |
我从这种堆叠闪电战中尝试了基本概念,并且奏效了。它取消了剩余的操作。请参阅下面的链接。
https://stackblitz.com/edit/angular-4ctwsd?file=src/app/app.component.ts
我在您的代码和我的代码之间看到的区别是,我使用的是
以下是参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import { Component } from '@angular/core'; import { of, from } from 'rxjs'; import { map, catchError, tap, retry} from 'rxjs/operators'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { name = 'Angular 6'; constructor() { of('a', 'b', 'c', 'd') .pipe( map(x => { if (x === 'c') { throw 'An error has occurred'; } return x; }), tap(x => console.log('In tap: ', x)), retry(3), catchError(() => of('caught error!')) ) .subscribe(x => console.log(x)); } } |
RXJS会抛出错误并停止执行。您在管道中应用的操作员是错误的选择。
您正在使用的'tap'运算符仅用于施加副作用,即对DOM,console.log进行更改,或更改组件上已获取的某些变量的值(即this.counter = someValue)。 tap运算符并不是要更改RXJS"流",它只会返回与接收到的相同的可观察值。 https://rxjs-dev.firebaseapp.com/api/operators/tap
另一方面,在流上起作用的运算符(例如" map")可能会引发错误。看到这个stackblitz
总的来说,代码是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | getData(): Observable { return this.httpGet('basePath').pipe( map(evt => { if (evt === null) { return throwError(new Error("No data found...")); } else { return evt; } }), concatMap(evt => { return this.httpGet(`childPath/${evt.serverResult}`); }), map(res => { return { "response2": res.serverResult }; }), retry(3), catchError(error => { console.log('error handled!'); return of(null); }) ) } private httpGet(someString: string): Observable<{ serverResult: number }> { return timer(1000).pipe( // fake a server call that takes 1 second map(_ => { // fake a server result // Comment out the valid return and uncomment the null return to see it in action //return null; return { serverResult: 1 } }) ); } |
如果您不想将错误转换为流中的有效值,请在订阅函数的错误回调中进行处理。
您还可以使用信号
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | httpGetSafe(path: string): Observable<Data> { const stopSignal$ = new Subject(); return this.http.get<Data>(path).pipe( map(data => { const isBad = data === null; if (isBad) { stopSignal$.next(); } return data; }), takeUntil(stopSignal$) ); } |
有时候,它比抛出错误更简单,更灵活...
可观察的函数总是内部package在try / catch块中。流中抛出的任何错误都将终止流,并向订阅者或操作员调用任何错误回调。
这里的问题是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | getData(id: String): Observable { return this.http.get(`${this.baseUrl}/path/${id}`).pipe( tap(evt => { if (evt == null) { throw new Error("No data found..."); } }), concatMap( evt => <Observable>( this.http.get( `${this.baseUrl}/path/relatedby/${evt.child_id}` ).map(res =>( {"response1":evt,"response2":res}) ) ) ), retry(3), catchError(this.handleError("getData", [])) );} |