Rxjs выполняет concatMap только один раз - PullRequest
0 голосов
/ 25 мая 2019

У меня есть две наблюдаемые, getUser и getUserAvatar . Оба они выдают два значения - кешируются немедленно с помощью BehaviorSubject и реальное после сетевого запроса.

Теперь код работает следующим образом:

1) Отправьте запрос на получение пользователя и немедленно отправьте кэшированного пользователя

2) После запуска кэшированного пользователя код попадает внутрь concatMap и в первый раз выполняет getUserAvatar

3) getUserAvatar отправляет запрос на сервер и немедленно отправляет кэшированный userAvatar

4) Все выполнено и кешированный пользователь вернул кешированный аватар

5) Через некоторое время реальный пользователь вернулся и getUser снова выдает значение

6) На этом шаге я хочу запретить вызов concatMap во второй раз , поскольку запрос к серверу уже выполняется, я просто хочу вернуться к 'USER LOADED.

sendGetRequest('/user/').pipe(
        concatMap(() => {
            // HERE, after user data loaded, I have url for his avatar
            return sendGetRequest('/avatar/').pipe();
        }),
        map(() => {
            return 'USER LOADED';
        })
    )

Код для запроса к серверу

sendGetRequest(url: string, ignoreCache?: boolean): any {

    let responseSubj = new Subject();

    const cachedData = this.cache.getItemForUrl(url);
    const cacheAllowed = cachedData && !ignoreCache;
    if (cacheAllowed) {
        responseSubj = new BehaviorSubject(cachedData);
    }

    const getFromServer = this.http.get(environment.API_SERVER_URL + url, this.addAuth()).pipe(
        filter((res: any) => {

            if (cacheAllowed && JSON.stringify(cachedData) === JSON.stringify(res)) {
                responseSubj.complete();
                return false;
            }

            this.cache.setItemForUrl(url, res).then(() => {
                responseSubj.complete();
            });
            return true;
        }),
        catchError((error, caught) => {
            console.log('ERROR FROM GET REQUEST', error);
            return throwError(error);
        })
    );


    return merge(responseSubj, getFromServer);
}

Ответы [ 2 ]

1 голос
/ 28 мая 2019

Итак, я думаю, что это то, что вы после:

https://stackblitz.com/edit/angular-2kaawf

Итак, как вы можете видеть, я не объявляю никаких тем для извлечения кэшированных результатов. Я не говорю, что вы не должны использовать темы. Вы просто не нуждались в них в этом случае. Я включил кнопку очистки кэша и перезагрузки, чтобы проиллюстрировать, для чего вы можете использовать тему.

Если вы перезагрузите страницу, вы увидите, что ранее использованные данные используются повторно. Однако при очистке кэшированных данных кэшированные данные исчезают, и после перезагрузки вы увидите «ноль».

Этот код будет работать как положено. Однако, если у вас будет 2 подписки на пользователя $ observable, вы получите некоторые неожиданные результаты. Чтобы исправить эти проблемы, загляните в оператор shareReplay;)

0 голосов
/ 28 мая 2019

Вы должны использовать exhaustMap вместо concatMap.

exhaustMap игнорировать другие значения до тех пор, пока эта наблюдаемая не завершится.

Например,

fromEvent(this.saveButton.nativeElement, 'click')
.pipe(
    exhaustMap(() => this.saveCourse(this.form.value))
)
.subscribe();

Если мы теперь нажмем кнопку «Сохранить», скажем, 5 раз подряд, мы увидим, что щелчки, которые мы сделали во время запроса на сохранение, все еще выполнялись там, где игнорировались, как и ожидалось!

Пример взят из angularuniveristy блог.

Подробное объяснение выхлопной карты

...