Составление зависимой от порядка цепочки Observable с несколькими асинхронными действиями - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь составить цепочку наблюдаемых в приложении Angular и пытаюсь найти порядок операций, чтобы заставить его работать по мере необходимости.Любые идеи / указания о том, как реализовать это, будут наиболее цениться.

Меня особенно интересует правильная последовательность операторов, чтобы существующая структура кода работала в нужном порядке, без обширного рефакторинга.

Вот что я пытаюсь достичь (в описании, затем псевдокод, затем упрощенная версия моего кода, поскольку он распространяется на несколько служб):

description

Каждый из следующих шагов является наблюдаемым, причем первым является точка, где вызывается 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 */ }
    );
}
...