【问题标题】:RXJS/Angular Prevent multiple HTTP on multiple subscribersRXJS/Angular 防止多个订阅者上的多个 HTTP
【发布时间】:2019-10-27 02:10:41
【问题描述】:

我有“mainData”服务,它由三部分组成:

  • currentPage 被分页器组件用来切换页面。可以随时更新。
  • folders 包含当前文件夹中的所有文件夹。有 2 个组件使用此 observable(文件夹内容列表的类型)
  • files 包含当前文件夹中的所有文件。有 3 个组件使用此 observable(文件夹内容列表的类型)

默认视图是没有文件夹的视图,因此我不想进行不必要的 HTTP 调用。

public currentPage = new ReplaySubject(1);
public folders: Observable<FLFolder[]>;
public files: Observable<FLFile[]>;

constructor(
  activatedRoute: ActivatedRoute,
  folderService: FolderService,
  fileService: FileService,
) {
  // Populate `this.currentPage`
  activatedRoute.queryParams.pipe(
    take(1),
    //  Wait until end of this sync tick. If no emission is made, it will use default in the next tick.
    takeUntil(timer(1, queueScheduler)),
    defaultIfEmpty<Params>({}),
  ).subscribe(query => {
    if (query.page) {
      this.currentPage = +query.page;
    } else {
      this.currentPage = 1;
    }
  });

  /** This observable is internal, only to be used by `folders` and `files` */
  const folderIDAndPage: Observable<[string, number]> = combineLatest(
    activatedRoute.url.pipe(
      switchMap(segments => folderService.getFoldersFromSegments(segments)),
      distinctUntilChanged(),
    ),
    this.currentPage.pipe(
      distinctUntilChanged(),
    ),
  ).pipe(
    // Prevent repeating HTTP somehow...
    publishReplay(1),
    refCount(),
  );

  this.folders = folderIDAndPage.pipe(
    switchMap(([folderID, page]) => folderService.getFfolders(folderID, page)),
    // Prevent repeating HTTP somehow...
    publishReplay(1),
    refCount(),
  );

  this.files = folderIDAndPage.pipe(
    switchMap(([folderID, page]) => fileService.getFiles(folderID, page)),
    // Prevent repeating HTTP somehow...
    publishReplay(1),
    refCount(),
  );
}

当没有订阅 folders 或 files 时,不会生成 HTTP。但即使一个人只订阅其中一个,folders 和 files 也会被填充(在进行 HTTP 调用时)并同时更新。

【问题讨论】:

    标签: angular typescript rxjs rxjs6


    【解决方案1】:

    this.folders 和 this.files 在此服务中没有被调用。组件是怎么回事?

    也许重构是为了?如果我离开了,请原谅我。

    我使用 getter 设置我的服务:

    private _currentUser = new BehaviorSubject<User>({} as User);
    

    那么你只能通过访问getter从组件中获取:

    public getCurrentUser(): Observable<User> {
        return this._currentUser.asObservable();
    }
    

    这样称呼更清楚。

    【讨论】:

      【解决方案2】:

      您能否在您的代码中进行以下更改并尝试 -

      const getFoldersFromSegments$ = activatedRoute.url.pipe(
        switchMap(segments => folderService.getFoldersFromSegments(segments)),
        distinctUntilChanged(),
        publishReplay(1),
        refCount(),
      );
      
      /** This observable is internal, only to be used by `folders` and `files` */
      const folderIDAndPage: Observable<[string, number]> = combineLatest(
        getFoldersFromSegments$,
        this.currentPage.pipe(
          distinctUntilChanged(),
        ),
      ).pipe(
        // Prevent repeating HTTP somehow...
        publishReplay(1),
        refCount(),
      );
      

      顺便说一句 - 你在 activatedRoute.queryParams observable 上使用了 take(1);这将使您的this.currentPage 只更改一次。但是你说,

      随时更新

      ,这不是矛盾吗?还是故意的?

      【讨论】:

      • 这是有意的,因为对 currentPage 的任何下一次更新都是通过 Subject.next 方法在分页器组件内发生的。另外,你能解释一下发生了什么变化吗?我不明白为什么将publishReply 和refCount 移动到流中会有所帮助。
      • @Akxe 基本上你想在订阅 combineLatest 时分享 API 的结果。现在,combinedLatest 会在任何一个可观察对象发出新值时评估它的所有可观察对象。通过在 api observable 上应用 publishreplay/refcount,我认为在所有 combineLatest observable 中都将使用相同的订阅。这是我的理论。由于我无法像您的场景那样设置我的代码,所以不确定它是否会起作用。如果您能说出此解决方案是否适合您,我将不胜感激。
      猜你喜欢
      • 2019-04-02
      • 2018-12-11
      • 1970-01-01
      • 2018-01-17
      • 2019-09-15
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多