Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge "static" observable with "dynamic" in rxjs 6?

I'm writing chrome extension and decided to wrap everything into streams, mostly for training and take a look into rxjs.

So I’m stuck with such a problem. I have two streams, one stream is static (don’t know how to correctly name it) and one dynamic.

A static stream is that one who emits value only when you subscribe to it (getPath$), it return value from a chrome storage. A dynamic (message$) stream is a stream which listening for events(messages).

So my goal is somehow to merge this two stream and every time when I’m receiving a message from message$ get value from a getPath$ and make some calculations based on two values.

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
    ) 
) 

I found how to do this in such a way:

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

Or

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

Seems like it's working, but it feels like I am doing wrong. Any suggestions or how to do it following best approaches? Also, please correct me in definitions.

UPD Here the full code: https://gist.github.com/ And the latest version which is work

const merged$ = message$.pipe(
   switchMap(sendedPath => combineLatest(
        path$,
        unit$
    ).pipe(
        map(([path, unit]) => [sendedPath, path, unit]))
    )
)
like image 450
Dmytro Filipenko Avatar asked Jan 29 '26 16:01

Dmytro Filipenko


1 Answers

What you name dynamic/static is similar to Hot and Cold Observables, but not exactly the same.

Your first approach with switchMap is mostly fine, except that you should recalculate it every time:

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

I have also changed switchMap to mergeMap, otherwise, you may "lost" some of the messages, see RxJS: Avoiding switchMap-Related Bugs


And also you may simplify your code a little bit:

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
like image 168
Oles Savluk Avatar answered Feb 01 '26 07:02

Oles Savluk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!