如何使RxJ可以观察到错误完成? [英] How to keep RxJs observable from completing on error?

查看:66
本文介绍了如何使RxJ可以观察到错误完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个成角反应形式,它可以进行简单的GET请求.例如,如果我应该得到某种HTTP错误.可观察的todo$现在已完成,我无法再更改搜索选项,然后单击以重试搜索.在我添加的演示中,我做了一个 stackblitz演示.初始化中的订阅,如果流上有错误,我将其捕获.捕获后,我再次调用初始化程序.这是可行的,但似乎是错误的错误处理方式.

I have an angular reactive form that makes a simple GET request. If for example, I should get some sort of HTTP error. The observable todo$ has now completed I can no longer change my search options and click to retry searching. I've made a stackblitz demo, in the demo I've added my subscription inside an initializer and if there is an error on the stream I catch it. After I catch it, I call the initializer again. This works but seems like the wrong way to handle errors.

我已经设置了表单,以便可以取消以前的HTTP请求.

I've set up the form so that I can cancel previous HTTP requests.

export class AppComponent implements OnDestroy {
  todos;
  loading = false;
  useFakeURL = false;
  todoSub$: Subscription;
  todo$: BehaviorSubject < string > = new BehaviorSubject < string > ('');

  @ViewChild('searchInput') searchInput: ElementRef;

  constructor(private provider: ExampleService) {
    this.init();
  }

  ngOnDestroy() {
    this.todoSub$.unsubscribe();
  }

  search() {
    const value = this.searchInput.nativeElement.value;
    this.todo$.next(value);
    this.useFakeURL = !this.useFakeURL;
  }

  private init(): void {
    this.todoSub$ = this.todo$.pipe(
        filter(val => !!val),
        tap(() => {
          this.loading = true;
        }),
        switchMap(() => this.provider.query(this.todo$.getValue(), this.useFakeURL)),
        catchError(error => {
          this.todo$.next('');
          this.init();
          return of([]);
        }),
      )
      .subscribe(
        todos => {
          this.loading = false;
          this.todos = todos;
        },
        err => {
          this.loading = false;
          this.todos = err;
        }
      );
  }
}

export class ExampleService {

  constructor(private http: HttpClient) {}

  query(todo, useFakeURL: boolean) {
    if (todo === 'all') {
      todo = '';
    }
    const url = useFakeURL ? 'poop' : `https://jsonplaceholder.typicode.com/todos/${todo}`;
    return this.http.get(url);
  }
}

<div class="container">
  <input #searchInput type="text" placeholder="Enter a number or enter 'all' to get all todos">
  <button (click)="search()">Get Todos</button>
</div>
<ul *ngIf="!loading && todos && todos.length">
  <li *ngFor="let todo of todos">
    <pre>
      {{todo | json}}
    </pre>
  </li>
</ul>
<pre *ngIf="!loading && todos && !todos.length">
  {{todos | json}}
</pre>
<div *ngIf="loading" class="loader">... LOADING</div>

推荐答案

如@kos所述,我在错误的位置捕获了错误.由于我切换到新的可观察对象,因此我应该在switchMap中捕获错误. UPDATED-DEMO

As mentioned by @kos I was catching the error in the wrong place. Since I switched to a new observable I should be catching the error inside switchMap. UPDATED-DEMO

search(term: Observable < string > ) {
  return term.pipe(
    filter(val => !!val),
    distinctUntilChanged(),
    debounceTime(500),
    // attached catchError to the inner observable here.
    switchMap(term => this.searchTodo(term).pipe(catchError(() => {
      return of({
        error: 'no todo found'
      });
    }))),
  );
}

这篇关于如何使RxJ可以观察到错误完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆