上下文:我正在@ngrx/effects项目中实现@ngrx/store并研究example app

问题:BookEffects class file的#50行中,为什么使用takeUntil(...)代替take(1)?在这种情况下,两者似乎都可以完成相同的任务。

@Injectable()
export class BookEffects {
  constructor(private actions$: Actions, private googleBooks: GoogleBooksService) { }

  @Effect()
  search$: Observable<Action> = this.actions$
    .ofType(book.ActionTypes.SEARCH)
    .debounceTime(300)
    .map((action: book.SearchAction) => action.payload)
    .switchMap(query => {
      if (query === '') {
        return empty();
      }

      const nextSearch$ = this.actions$.ofType(book.ActionTypes.SEARCH).skip(1);

      return this.googleBooks.searchBooks(query)
        .takeUntil(nextSearch$)
        .map(books => new book.SearchCompleteAction(books))
        .catch(() => of(new book.SearchCompleteAction([])));
    });
}

这是Google Books service file:

@Injectable()
export class GoogleBooksService {
  private API_PATH: string = 'https://www.googleapis.com/books/v1/volumes';

  constructor(private http: Http) {}

  searchBooks(queryTitle: string): Observable<Book[]> {
    return this.http.get(`${this.API_PATH}?q=${queryTitle}`)
      .map(res => res.json().items || []);
  }

  retrieveBook(volumeId: string): Observable<Book> {
    return this.http.get(`${this.API_PATH}/${volumeId}`)
      .map(res => res.json());
  }
}

最佳答案

要了解为什么使用takeUntil,可能不做关于searchBooks的实现的任何假设。
searchBooks服务方法返回一个可观察的Book[]。该可观察性不一定必须完成;例如,如果数据库发生更改,它可能会发出其他结果(Firebase的AngularFire2可观察对象就是这种情况)。但是,如果使用take(1),后续结果将被忽略。如果使用takeUntil,后续结果将继续影响操作,直到启动下一次搜索。

但是,我不认为takeUntil是必不可少的,因为switchMap会处理所有事情(内部可观察的对象将不再被订阅,等等)。
example-app的作者似乎已经以不依赖于服务实现的方式实现了搜索效果。

使用基于Http的简单基于searchBooks的实现,我看不到为什么需要take(1)takeUntil-因为将完成可观察到的操作,并且switchMap将确保不会发出用于过时搜索的SearchCompleteAction操作。

10-04 16:52