RXJS/Angular Prevent multiple HTTP on multiple subscribers

不羁岁月 提交于 2019-12-25 01:15:51

问题


I have "mainData" service, it consists of 3 parts:

  • currentPage used by paginator component to switch page. Can be updated at any point.
  • folders contains all folders in the current folder. There are 2 components that use this observable (Types of listing of folder content)
  • files contains all files in the current folder. There are 3 components that use this observable (Types of listing of folder content)

The default view is the one without folders, thus I would like not to make unnecessary HTTP calls.

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(),
  );
}

When there is no subscribe to either folders, or files, no HTTP are made. But even if one subscribes to only one of them, both folders and files get populated (while making the HTTP call) and updated at the same time.


回答1:


this.folders and this.files are not being called here in this service. What's going on with the components?

Perhaps a refactor is in order? Forgive me if I'm off.

I setup my services with getters:

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

Then you can only get it from a component by accessing the getter:

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

This way it's more clear to call it.




回答2:


Can you please make the following change in your code and try -

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(),
);

BTW - You have used take(1) on activatedRoute.queryParams observable; It will make your this.currentPage to be changed only once. But you said,

Can be updated at any point

, so is it not a contradiction? Or it is intentional?



来源:https://stackoverflow.com/questions/56564281/rxjs-angular-prevent-multiple-http-on-multiple-subscribers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!