Использование forkJoin в качестве разрешаемого оператора в канале RxJS 6

Конечная цель
У меня есть метод регистрации пользователя/устройства. В нем мне нужно:

  1. Проверить, готово ли локальное хранилище
  2. Если это так, проверьте отдельно для deviceId и token
  3. Если идентификатор устройства или токен не найдены, вызовите конечную точку регистрации.

Где я нахожусь
Во время сборки и для простоты я не занимался токенизацией. Я работал только с deviceId, и нижеприведенное работало/работает отлично.

Я вызываю вспомогательный метод isStorageReady, проверяю ответ, затем вызываю вспомогательный метод getDeviceId и проверяю этот ответ.

this.isStorageReadyAsync()
    .pipe(
        map(storageResponse => {
            // check storageResponse
            // if undefined throw error
            // error picked up by retryPipeline
            // if retryPipeline exhausted picked up 
            // by errorPipeline and stream is stopped
            if (storageRes === undefined ||
                storageRes['LOCALSTORAGE'] === undefined ||
                storageRes['LOCALSTORAGE'] === '') throw 'storageRes or 
                storageRes.LOCALSTORAGE are undefined or empty';
        }),
        flatMap(_ => this.getStoredDeviceIdAsync()),
        map(deviceId => {
            return iif (() => deviceId === undefined || 
                             deviceId === null || 
                             deviceId === '',
                       // no deviceId stored on device
                       // register device to get deviceId
                       this.registerDeviceAsync(), 
                       // deviceId found in local storage
                       of({id: deviceId, new: false}))
        }),
        this.storeDeviceIdPipeline, // store deviceId
        this.retryPipeline, // retry if e.g. experiencing network issues
        this.errorPipeline // catch and handle errors
    )

Где я застрял
У меня есть второй вспомогательный метод, getStoredTokenAsync(), который я хотел бы вызывать параллельно с getStoredDeviceIdAsync(). Я пробовал использовать forkJoin и передавать массив в следующий за ним оператор map, но моему машинописному линтеру это совсем не нравится. Все, что предшествует forkJoin, подчеркивается, как если бы это было ошибкой, и ошибка выглядит следующим образом:

Argument of type OperatorFunction is not assignable to parameter of type OperatorFunction. Type void is not assignable to type {}.

Так что я не совсем понимаю. Я надеялся использовать что-то вроде этого:

...
forkJoin([this.getStoredDeviceIdAsync(), this.getStoredTokenAsync()]),
map(authArr => {
   let deviceId = authArr[0];
   let token = authArr[1];
   ...
})
...

Карта в третьей строке что-то возвращает? Я вижу бросок, но не возвращаемое значение

LookForAngular 29.05.2019 16:29

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

shaunmwa 29.05.2019 16:44

Проверка на наличие ошибок на карте - это нормально. В любом случае она должна что-то вернуть ( storageResponse ) или показать подчеркивание.

LookForAngular 29.05.2019 16:47

Тип void, вероятно, является картой. Я предлагаю вам использовать оператор flatMapTo, чтобы объявить, что вы не заинтересованы в предыдущем вводе

LookForAngular 29.05.2019 16:48

Ах! Возврат storageResponse действительно решает первую проблему. Спасибо. Не слышал о flatMapTo. Где документация на него? Что-то гуглю и не могу найти. Кроме того, какие-либо сведения об использовании forkJoin для параллельного запуска двух вспомогательных методов?

shaunmwa 29.05.2019 16:59

Если сами вспомогательные методы возвращают наблюдаемый объект, вы можете сохранить их в массив, как писали ранее. Просто не используйте forkjoin непосредственно внутри канала, так как forkjoin не является оператором. сопоставьте его с помощью операторов слияния/исчерпания/переключателя/concatMap

LookForAngular 29.05.2019 17:23

С помощью forkJoin вы можете направить оба потока внутрь forkJoin и map, как обычно. flatMap теперь называется mergeMap

Julius 29.05.2019 20:51

Милая! Встраивание forkJoin внутрь mergeMapTo отлично работает!

shaunmwa 30.05.2019 02:26
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
48
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спасибо обоим комментаторам, LookForAngular и Юлиусу Дзидзявичюсу, за помощь в составлении! Я предоставляю полный ответ здесь, если это полезно для других. Также предоставление большего количества кода для некоторого дополнительного контекста.

Перед вызовом mergeMapTo выполняется некоторая общая проверка ответа. Результат этого не потребляется, поэтому использование mergeMapTo уместно (подразумевается, что все, что было до этого, не имеет отношения к тому, что происходит внутри mergeMapTo).

mergeMap существенно сглаживает внутреннюю наблюдаемую, которая обеспечивается моим вызовом iif. Вывод из mergeMap направляется в мой конвейер хранилища (это просто вызов map), который обрабатывает всю логику, связанную с аутентификацией пользователя и т. д.

pipe(
    ...
    mergeMapTo(forkJoin([this.getStoredDeviceIdAsync(), this.getStoredTokenAsync()])),
    mergeMap(authArr => {
        let deviceId = authArr[0];
        let token = authArr[1];
        return iif (() => deviceId === undefined || deviceId === null || deviceId === '' ||
                         token === undefined || token === null || token === '',
                         this.registerDeviceAsync(), // register device to get deviceId and token
                         of({deviceId: deviceId, token: token, new: false})) 
    }),
    this.storeDeviceIdTokenPipeline,
    this._config.retryPipeline, // generic retryWhen procedure
    this._config.errorPipeline // generic catchError procedure
)

Другие вопросы по теме