RXJS / Angular Предотвратить несколько HTTP на нескольких подписчиков - PullRequest
0 голосов
/ 12 июня 2019

У меня есть служба «mainData», она состоит из 3 частей:

  • currentPage, используемая компонентом paginator для переключения страницы.Может быть обновлено в любой момент.
  • folders содержит все папки в текущей папке.Есть 2 компонентов, которые используют эту наблюдаемую (Типы перечисления содержимого папки)
  • files содержит все файлы в текущей папке.Существуют 3 компоненты, которые используют эту наблюдаемую (Типы перечисления содержимого папки)

По умолчанию используется представление без папок, поэтому я не хотел бы делать ненужные вызовы 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-вызова) и обновляются одновременно.

Ответы [ 2 ]

0 голосов
/ 12 июня 2019

Пожалуйста, внесите следующие изменения в свой код и попробуйте -

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

Кстати - Вы использовали take(1) на activatedRoute.queryParams наблюдаемый; Ваш this.currentPage будет изменен только один раз. Но вы сказали,

Может быть обновлено в любой момент

, разве это не противоречие? Или это намеренно?

0 голосов
/ 12 июня 2019

this.folders и this.files здесь не называются в этой услуге.Что происходит с компонентами?

Возможно, рефактор в порядке?Простите, если я отключен.

Я настраиваю свои службы с помощью геттеров:

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

Тогда вы можете получить его только из компонента, получив доступ к геттеру:

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

Так проще называть это.

...