在 Angular 中使用 Observable 响应 api 请求,然后将任何更改推送到控制器

In Angular using Observable to respond to an api request and then push any changes to the controller

我目前正在使用 angular 5,但这只是一个一般的 RxJs 问题。我希望能够用数据响应控制器对 api 的数据的请求,但也希望在值变得陈旧时随时推送更改。我目前正在尝试使用多播来实现这一点,但这似乎不正确,因为只收到了初始值。

export class EditorService {
  private getSubject = new Subject<null>();

  onLanguageChange() {
    // currentLanguage is a model so will be updated by angular
    this.getSubject.next();
  }

  get(): Observable<DeltaStatic> {
    const get = () => {
      return this.http.get<BackEndResponse<MasterBlob<DeltaStatic|string>>>(
        `${backendEndPoint}/get-all`,
      ).pipe(
        map(blob => blob.data[this.currentLanguage][this.currentKey].quillBlob)
      );
    };

    return get().pipe(
      multicast(this.getSubject),
      refCount(),
      switchMap(get),
    );
  }
}

另一种感觉稍微更惯用的选择是仅使用带有 switchMap 的主题,但我不想在订阅后必须从控制器触发下一个以获取第一个值:

export class EditorService {
  private getSubject = new Subject<null>();

  onLanguageChange() {
    // currentLanguage is a model so will be updated by angular
    this.getSubject.next();
  }

  get(): Observable<DeltaStatic> {
    const get = () => {
      return this.http.get<BackEndResponse<MasterBlob<DeltaStatic|string>>>(
        `${backendEndPoint}/get-all`,
      ).pipe(
        map(blob => blob.data[this.currentLanguage][this.currentKey].quillBlob)
      );
    };

    return this.getSubject.pipe(
      switchMap(get),
    );
  }
}

@Component({
  selector: 'editor',
  templateUrl: './editor.component.html',
  styleUrls: ['./editor.component.scss']
})
export class EditorComponent implements AfterViewInit {
  constructor(private editorService: EditorService) {}

  ngAfterViewInit() {
      this.editorService.get().subscribe(data => {...});
    this.editorService.getSubject.next();
  }
}

最后,我尝试了使用 ReplaySubject 的解决方案,但这需要我订阅服务中的初始 Observable,这违背了等待调用直到控制器需要某些东西并调用的最佳实践订阅。我也觉得我总是求助于 ReplaySubject,因为它是最容易破解的,但必须有更好的方法来实现这一点。

如果您不想在订阅者之间共享数据,这里有一个解决方案。跟你的差不多,就是用startWith立即触发初始请求,避免了你说的问题:

export class EditorService {

  private languageChange$ = new Subject<void>();

  public onLanguageChange() {
    this.languageChange$.next();
  }

  public get(): Observable<DeltaStatic> {
    // By appending startWith(), which is short for startWith(undefined),
    // we ensure that we trigger the request once initially.
    return this.languageChange$
        .startWith(undefined)
        .switchMap(() => this.requestData());
  }

  private requestData() {
    return this.http.get<BackEndResponse<MasterBlob<DeltaStatic|string>>>(`${backendEndPoint}/get-all`)
      .pipe(
        map(blob => blob.data[this.currentLanguage][this.currentKey].quillBlob)
      );
  }

}

如果你想在订阅者之间共享刷新的数据,你可以这样做,虽然我没有测试它:

export class EditorService {

  private refreshed$ = new Subject<DeltaStatic>();

  public onLanguageChange() {
    this.requestData().subscribe(data => this.refreshed$.next(data));
  }

  public get(): Observable<DeltaStatic> {
    // Trigger request immediately, then concat any future updates
    // to it.
    return this.requestData().concat(this.refreshed$);
  }

  private requestData() {
    return this.http.get<BackEndResponse<MasterBlob<DeltaStatic|string>>>(`${backendEndPoint}/get-all`)
      .pipe(
        map(blob => blob.data[this.currentLanguage][this.currentKey].quillBlob)
      );
  }

}