Как объединить «статические» наблюдаемые с «динамическими» в rxjs 6? - PullRequest
0 голосов
/ 11 сентября 2018

Я пишу расширение для Chrome и решил обернуть все в потоки, в основном для обучения и взглянуть на rxjs.

Так что я застрял с такой проблемой.У меня есть два потока, один поток статический (не знаю, как правильно его назвать) и один динамический .

Статический поток - это тот, кто генерирует значение только тогда, когда вы подписываетесь на него ( getPath $ ), и возвращает значение из хранилища Chrome.Динамический ( message $ ) поток - это поток, который прослушивает события (сообщения).

Так что моя цель состоит в том, чтобы каким-то образом объединить эти два потока и каждый раз, когда я получаю сообщение от message $ , получать значение из getPath $ и делать некоторыерасчеты основаны на двух значениях.

type Handler = (
    message: any, 
    sender: any, 
    sendResponse: (response: any) => void
) => void; 

type Values  = string | string[];

const getValues = (values: Values) => (cb) => chrome.storage.local.get(values, cb) 
const getPathBinded = bindCallback(getValues('path')) 
const getPath$ = getPathBinded() 

const message$ = fromEventPattern( 
   (handler: Handler) => chrome.runtime.onMessage.addListener(handler), 
   (handler: Handler) => chrome.runtime.onMessage.removeListener(handler), 
   (message, sender, sendResponse) => ({ message, sender, sendResponse }) 
).pipe( 
    map(
       ({ message }) => message
    ) 
) 

Я нашел, как это сделать таким образом:

message$.pipe( 
    switchMap( 
        _ => getPath$, 
        (oV, iV) => {
            //doing some calculation
        } 
    ) 
 )

Или

combineLatest(
  message$,
  getPath$,
).pipe(
    map((a, b) => {
       //doing some calculation
    })
)

Похоже, это работает,но такое чувство, что я делаю не так.Любые предложения или как это сделать, следуя лучшим подходам?Также, пожалуйста, поправьте меня в определениях.

UPD Здесь полный код: https://gist.github.com/ и последняя версия, которая работает

const merged$ = message$.pipe(
   switchMap(sendedPath => combineLatest(
        path$,
        unit$
    ).pipe(
        map(([path, unit]) => [sendedPath, path, unit]))
    )
)

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

То, что вы называете динамическим / статическим, похоже на Горячие и холодные наблюдаемые , но не совсем одно и то же.

Ваш первый подход с switchMap в основном хорош, за исключением того, что вы должныпересчитывайте его каждый раз:

const combined$ = messages$.pipe(
  mergeMap(() => getPathBinded(), (message, path) => { ... })
)

Я также изменил switchMap на mergeMap, в противном случае вы можете «потерять» некоторые сообщения, см. RxJS: Избегание ошибок, связанных с switchMap


А также вы можете немного упростить свой код:

const getStorage = bindCallback(chrome.storage.local.get); 
// use it as: const path$ = getStorage("path")

const message$ = fromEvent(chrome.runtime.onMessage);    
// should be enough, since you are only using default methods
0 голосов
/ 11 сентября 2018

Если ваша цель

, объединить эти два потока, и каждый раз, когда я получаю сообщение из сообщения $, получаю значение из getPath $ и выполняю некоторые вычисления на основе двух значений

похоже, что подход switchMap является правильным.switchMap в данном случае означает: в любое время, когда я получаю уведомление от message$, я переключаюсь на другое Observable, в этом случае возвращаемое, вызывая getPath$.

Если вы хотите что-то сделатьс обоими значениями, то, вероятно, вы не можете позволить себе игнорировать значение, сообщаемое message$, что и делает ваш код в настоящее время, и вы должны передать map в результат getPath$, чтобы вы могли создатьобъект, содержащий 2 значения, заявленные 2 Observables, и передать такой объект в следующий расчет.Код должен выглядеть как

message$.pipe( 
    switchMap( 
        message => getPath$.pipe(map(path => ({message, path}))), 
        map(({message, path}) => {
            //doing some calculation
        })
    ) 
 )
...