【问题标题】:Why use .takeUntil() over .take(1) with Http service?为什么使用 .takeUntil() 而不是 .take(1) 与 Http 服务?
【发布时间】:2017-01-15 03:06:50
【问题描述】:

背景:我正致力于在@ngrx/store 项目中实施@ngrx/effects 并研究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());
  }
}

【问题讨论】:

  • 请包含代码本身,而不是屏幕截图。而且,顺便说一句,您可以在 GitHub 链接中包含行号,例如 this(按住 shift 键单击行号,这些行将突出显示,等等)
  • @cartant 已修复。我只是想在此处包含行号,而不是让人们点击。但是感谢 Github 链接提示。

标签: angular rxjs ngrx


【解决方案1】:

要了解为什么使用takeUntil,对searchBooks 的实现不做任何假设可能会有所帮助。

searchBooks 服务方法返回 Book[] 的 observable。那个 observable 不一定要完成;例如,如果数据库发生变化,它可能会发出额外的结果(这就是 Firebase 的 AngularFire2 observables 发生的情况)。但是,如果使用take(1),则后续结果将被忽略。如果使用takeUntil,则后续结果将继续影响操作,直到启动下一次搜索。

但是,我认为 takeUntil 不是必需的,因为 switchMap 会处理事情(内部的 observable 将被取消订阅等)。

example-app 的作者似乎以不依赖于服务实现的方式实现了搜索效果。

通过简单的、基于HttpsearchBooks 实现,我不明白为什么需要take(1)takeUntil - 因为observable 将完成并且switchMap 将确保SearchCompleteAction不会发出针对过时搜索的操作。

【讨论】:

  • 很好的解释。谢谢你用关注点分离锤子砸我的头。
  • 我不是专家,但我认为更喜欢 takeUntil 的一个原因是,如果使用 take(1),如果 observable 从不发射,订阅将不会被取消。
【解决方案2】:

take(n) 从可观察序列的开头返回指定数量的连续元素

takeUntil(Observable | Promise) 从源 observable 序列返回值,直到另一个 observable 序列或 Promise 产生值。您可能应该使用 takeUntil 来管理您的 RxJS 订阅。

1) 当你杀死你的流时它会触发一个完成事件

2) 更少的实际订阅点数(因为更少调用subscribe

更多信息请阅读这篇文章https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87#.ge4d447b6

【讨论】:

  • 没有帮助。是的,我知道 .take() 和 .takeUntil() 之间的区别,但在这种特定情况下,我们正在处理 Http 获取请求。两者都应该工作,因为我们知道 Http.get 只会触发一次,对吧?对于您的观点:1) .take(1) 也会触发完成事件,并且 2)它不会产生更多的订阅点。这篇文章很好,但没有解决我的问题——为什么在这种特定情况下我们不使用.take(1)?那篇文章甚至提到使用 .take(n) 作为替代方案!
猜你喜欢
  • 2019-11-15
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
相关资源
最近更新 更多