如何控制服务调用的流程,使用rxjs与Angular 9?

问题描述 投票:0回答:1

我的代码是这样的。

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$)接收到的值,现在因为它们是异步的,所以我的userContext: UserContext;在第2个服务执行时是空的。

我还需要userContext.companyCode & GroupId用于未来的调用,因此我需要一种方法将其保留在某个地方,以便后续调用。

我尝试了resolver和APP_INT......但后来发现这两个地方的目的都不对。

angular typescript async-await rxjs observable
1个回答
0
投票

你已经使用了 "shareReplay(1)", tap((val: ...) shareReplay你唯一要做的就是把这个Observable的结果用在你想用的地方。

userAnnouncements$ = this.userContext$.pipe(mergeMap((userContextData) => {
    return this.http.post<Announcement>('someUrl',
        {
        countryCode: userContextData.countryCode, 
        companyGroupId: userContextData.companyGroupId,
        }
    );
}));

1
投票

我在等你的回答。

如果你 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无效未定义那么,之前对 userContext$ 是为了实现该属性。

_userContext 可能是静态的,这取决于你的依赖注入策略。如果你想让每个服务都存储自己的 _userContext罚款。即使 MyService 是单人的,那么 _userContext 不应该是静态的。否则,一个静态的 _userContext 是需要在所有服务实例中共享的。

此外,你可以过载 userAnnouncements$ 迫使 UserContext 重新获取。如果需要的话,那就很有意思了。

希望能帮到你。


0
投票

不知道这是否是你所要求的,但你可以使用 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
          });
      }
  );

那你只有一个订阅

© www.soinside.com 2019 - 2024. All rights reserved.