Как контролировать поток сервисных вызовов, используя rx js с Angular 9? - PullRequest
0 голосов
/ 09 мая 2020

Мой код выглядит следующим образом:

userContext: UserContext;
  userContext$ = this.http.get<UserContext>("assets/api/userContext.json", {}).pipe(
      shareReplay(1),
      tap((val: UserContext) => {
        this.userContext = val;
        console.log(this.userContext);
      })
  );
  userAnnouncements$ = this.http.post<Announcement>(this.userAnnouncementsService,
    {
      countryCode: this.userContext.countryCode, 
      companyGroupId: this.userContext.companyGroupId,
    }
  );

Как мы можем ясно видеть, 2-я служба (userAnnouncements $) нуждается в значениях, полученных 1-й службой (userContext $), теперь, поскольку они асинхронны c my userContext: UserContext; пуст, пока выполняется вторая служба.

Мне также понадобятся userContext.companyCode и GroupId для будущих вызовов, поэтому мне нужен способ сохранить его где-нибудь для последующих вызовов.

Я пробовал resolver и APP_INT ... но потом понял, что это неправильное назначение обоих мест.

Ответы [ 3 ]

1 голос
/ 09 мая 2020

Я ожидал вашего ответа.

Если вы UserContext - это что-то, что должно вызываться один раз, как я уже упоминал, вы можете думать об этом как о синглтоне.
Получите его один раз, затем кешируйте это внутри вашего сервиса.

class MyService {

    private _userContext: UserContext | undefined;

    constructor (private http: BackgroundService) { }

    userContext$ = this.http.get<UserContext>(`url`).then(ctx => {
        console.log(ctx);
        this._userContext = ctx;
        return ctx;
    });

    userAnnouncements$ = (): Promise<Announcement> => 
        this._userContext
            ? this.userAnnouncement(this._userContext)
            : this.userContext$.then(ctx => this.userAnnouncement(ctx));

    private userAnnouncement = (ctx: UserContext): Promise<Announcement> =>
        this.http.post<Announcement>(`url`, {
            countryCode: ctx.countryCode,
            companyGroupIp: ctx.companyGroupIp
        });
}

interface BackgroundService { // aka HttpClient
    get: <TResult>(url: string) => Promise<TResult>;
    post: <TResult>(url: string, body: any) => Promise<TResult>;
}

Я только что скопировал HttpClient только для того, чтобы правильно его скомпилировать. Вы можете забыть об этом.

Дело в том, что у вашего класса обслуживания есть внутреннее свойство UserContext. Любой вызов userContext$ предоставит этот объект и кеширует внутри службы.
Если вызов userAnnouncements$ выполнен, он использует кешированный UserContext. Каждый раз, когда вызов userAnnouncements$ выполняется перед любым вызовом userContext$, поэтому UserContext равен null или undefined , тогда предыдущий вызов userContext$ выполняется для выполнить свойство.

_userContext может быть c в зависимости от вашей политики внедрения зависимостей. Если вы хотите, чтобы каждый сервис хранил свой _userContext, отлично. Даже если MyService одноэлементный, тогда _userContext не должен быть c. В противном случае для обмена всеми экземплярами службы требуется статистика c _userContext.

Более того, вы можете перегрузить userAnnouncements$, чтобы принудительно выполнить повторную выборку UserContext. Если понадобится, это было бы интересно.

Надеюсь, это поможет.

0 голосов
/ 09 мая 2020

Вы уже используете shareReplay, единственное, что вам нужно сделать, это использовать результат этого Observable где угодно.

userAnnouncements$ = this.userContext$.pipe(mergeMap((userContextData) => {
    return this.http.post<Announcement>('someUrl',
        {
        countryCode: userContextData.countryCode, 
        companyGroupId: userContextData.companyGroupId,
        }
    );
}));
0 голосов
/ 09 мая 2020

Не уверен, что это то, о чем вы просите, но вы можете использовать switchMap

userContext: UserContext;
  userContext$ = this.http.get<UserContext>("assets/api/userContext.json", {}).pipe(
      tap((val: UserContext) => {
        this.userContext = val;
        console.log(this.userContext);
      }),
      switchMap((val: UserContext) => {
          return this.http.post<Announcement>(this.userAnnouncementsService, 
          {
              countryCode: val.countryCode,
              companyGroupId: val.companyGroupId
          });
      }
  );

Тогда у вас будет только одна подписка

...