kefirjs / kefir

A Reactive Programming library for JavaScript
https://kefirjs.github.io/kefir/
MIT License
1.87k stars 97 forks source link

How to resolve circular dependencies? #249

Open jeron-diovis opened 6 years ago

jeron-diovis commented 6 years ago

I have a situation almost like here: to send request I need data from some stream, and that stream should be updated when request is completed. I.e., it's a circular dependency.

In RxJS this problem is recommended to solve either with intermediate Subject or with expand operator (which I don't understand for now – looks just like flatMap, what's the difference?)

Kefir does not have subjects, but it has pool. Pool does the trick, but in general this solution looks just like this: pool is subscribed to itself. The problem is that such pool after activation always remains active:

screenshot 2017-10-02 12 56 16

Doc says that pool never ends, but there is nothing about "never deactivates". To deactivate such pool I should either terminate it at all, or unplug it from itself.

Both cases mean writing some code specially for this purpose – I can't just forget about this pool relying on deactivation of it's single consumer, defined somewhere far far away.

Let say I can't or don't want to write this special code.

So my questions are:

  1. Is it ok in general that pool isn't deactivated in described situation? Active stream with no subscriptions looks strange.

  2. Is there some "official" way of resolving circular dependencies in Kefir? Should I really use pool and explicitly terminate / unplug it? Or should I install kefir-bus package and implement Subject-like solution? Like this:

    const inputBus = KefirBus()
    const request$ = inputBus
    .sampledBy(...some signal...)
    .flatMap(...api call...)
    // just "tap into stream", not `observe`, 
    // to don't cause activation before it's really needed
    .map(x => {
    inputBus.value(...)
    return x
    })

    Or smth else?

mAAdhaTTah commented 6 years ago

Is it ok in general that pool isn't deactivated in described situation? Active stream with no subscriptions looks strange.

It might be OK if the resources that are left open as a result of the stream never getting deactivated don't cause a memory leak. That said, I feel like this is a bug, so I'll take a look at that.

Is there some "official" way of resolving circular dependencies in Kefir?

Not really; I'm currently using pool the way you do but experience some glitchy behavior that I think is unavoidable given Observable's sync nature, so my plan is to refactor the circular dependency to manage it a bit more manually. Using KefirBus may be another way of handling it, but it kind of depends on the desired behavior of the circular stream.