用多个异步动作组成一个与订单相关的Observable链

时间:2019-02-02 12:29:20

标签: angular rxjs observable

我正在尝试在Angular应用程序中组成一系列可观察的对象,并努力寻找操作顺序以使其按需工作。任何有关如何实现此目标的见解/指针将不胜感激。

我特别感兴趣的运营商做出的期望的顺序对现有代码结构工作的正确的顺序,而无需大量的重构。

这是我要实现的目标(在描述中,然后是伪代码,然后是代码的简化版本,因为它分布在多个服务中):

说明

每个以下步骤的是可观察到的,与所述第一个是其中subscribe()被称为点。

1:成功登录后,初始化用户服务。这是可观察的,将立即订阅。

2:在此初始化期间,检查内容是否陈旧:获取一个远程JSON文件,并将其中的值与本地存储的值进行比较。如果它们不同(内容已过时),请刷新内容缓存。

3:在检查内容之后,调用两个附加服务以获取JSON文件-首先在高速缓存中查找它们,然后从远程服务器获取。

订单是步骤2和3之间重要 - 在步骤2之前步骤3开始必须完成。对于步骤3中的服务呼叫,顺序并不重要。

如果我被记录的每一步,我希望看到这样的事情,如果内容是陈旧的:

logon success, initializing user
content is stale, flushing cached content
flushing cached content complete
fetching content
fetching domain
domain fetch complete
content fetch complete

,如果内容不陈旧:

logon success, initializing user
content is not stale
fetching content
fetching domain
content fetch complete
domain fetch complete

伪代码

logon
    on success, (initialize user with logon response)$.subscribe()


(initialize user with logon response)$
    // other stuff happens ... 

    return (fetch remote file and act on content)$ 
        then 
            (get content file foo)$, (get content file bar)$


(fetch remote file and act on content)$ 
    if content is stale 
        return (flush cached content)$
    else 
        return (empty observable)$


(get content file xxx)$
    if file is in cache
        return (retrieve file from cache)$
    else 
        return (fetch remote file)$

简化代码

// login-view.component.ts 
loginClick() {
    this.logonUserService
        .logon(credentials)
        .subscribe((logonResponse) => this.userService.initialize(logonResponse).subscribe());
}

// user.service.ts
initialize(logonResponse) {
    // do stuff with logonResponse, then... 

    return this.checkContentFreshnessService.initialize()
        .pipe(switchMap(() => forkJoin(
            this.contentService.initialize(),
            this.domainService.initialize()
        ));
}

// check-content-freshness.service.ts 
initialize(): Observable<any> {
    return this.contentService.getPublishSummary().pipe(
        tap(
            publishSummary => {
                const isContentStale = publishSummary.changesetId === this.contentService.changesetId;

                return iif(
                    () => isContentStale,
                    this.contentService.flushCache(),
                    of(true)
                );
            }
        )
    );
}

// content.service.ts & domain.service.ts are both essentially
initialize(): Observable<any> {
    const path = this.contentService.getContentPath(contentId);
    // or: const path = this.contentService.getDomainPath();

    return this.contentService.get(path).pipe(
        tap(response => { /* do something locally with response */ }
    );
}

0 个答案:

没有答案