1

以下是解决同一问题的两种方法,即对用户在文本框中输入的某些字符进行响应式搜索。第一个解决方案来自ngrx 示例,第二个解决方案来自egghead即时搜索课程。

  • 第一个解决方案使用Observable,而第二个使用Subject.
  • Observable解决方案takeUntil只调用一次服务器。该Subject解决方案使用distinctUntilChanged.

有人可以解释这两种方法的优缺点吗?

使用 Observable 搜索:

@Injectable()
export class BookEffects {

  @Effect()
  search$: Observable<Action> = this.actions$
    .ofType(book.ActionTypes.SEARCH)
    .debounceTime(300)
    .map(toPayload)
    .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([])));
    });

    constructor(private actions$: Actions, private googleBooks: GoogleBooksService) { }
}

@Component({
  selector: 'bc-find-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <bc-book-search [query]="searchQuery$ | async" [searching]="loading$ | async" (search)="search($event)"></bc-book-search>
    <bc-book-preview-list [books]="books$ | async"></bc-book-preview-list>
  `
})
export class FindBookPageComponent {
  searchQuery$: Observable<string>;
  books$: Observable<Book[]>;
  loading$: Observable<boolean>;

  constructor(private store: Store<fromRoot.State>) {
    this.searchQuery$ = store.select(fromRoot.getSearchQuery).take(1);
    this.books$ = store.select(fromRoot.getSearchResults);
    this.loading$ = store.select(fromRoot.getSearchLoading);
  }

  search(query: string) {
    this.store.dispatch(new book.SearchAction(query));
  }
}

使用主题搜索:

import { Component } from '@angular/core';
import { WikipediaSearchService } from './wikipedia-search.service';
import { Subject } from 'rxjs/Subject';

//application wide shared Rx operators
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/switchMap';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  items:Array<string>;
  term$ = new Subject<string>();
  constructor(private service:WikipediaSearchService) {

    this.term$
        .debounceTime(400)
        .distinctUntilChanged()
        .switchMap(term => this.service.search(term))
        .subscribe(results => this.items = results);
  }
}

<div>
  <h2>Wikipedia Search</h2>
  <input (input)="term$.next($event.target.value)">
  <ul>
    <li *ngFor="let item of items">{{item}}</li>
  </ul>
</div>
4

1 回答 1

2

行为主题是一种主题,主题是一种特殊类型的可观察对象,因此您可以像订阅任何其他可观察对象一样订阅消息。行为主体的独特特征是:

  • 行为主体需要一个初始值,因为它必须始终在订阅时返回一个值,即使它没有收到 next()
  • 订阅后,它会返回主题的最后一个值。常规可观察对象仅在它在任何时候收到 onnext 时触发,您可以使用 getValue() 方法在不可观察代码中检索主题的最后一个值。
  • 与可观察对象相比,对象的独特特征是:

除了作为可观察对象之外,它还是一个观察者,因此除了订阅它之外,您还可以向主题发送值。此外,您可以使用行为主体上的 asobservable() 方法从行为主体中获取可观察对象。

Observable 是一个 Generic,而 Behavior 主体在技术上是 Observable 的子类型,因为行为主体是具有特定品质的 observable。

可以使用 subject.asobservable() 从常规主题和行为主题创建可观察对象。唯一的区别是您不能使用 next() 方法将值发送到可观察对象。

在 angular2 服务中,我会将行为主题用于数据服务,因为 Angular 服务通常在组件之前初始化,并且行为主题确保使用该服务的组件接收到最后更新的数据,即使自组件订阅此数据以来没有新的更新也是如此. 简而言之,在 observable/subject/BehaviorSubject 等方面有很多相似之处,这取决于您的需要。

于 2017-03-06T20:50:25.237 回答