Fork me on GitHub
#re-frame
<
2018-07-02
>
manutter5113:07:25

Something is puzzling me. I have a subscription that returns all the forms in app-db. I pass that as an input signal to a subscription that pulls out a specific form from the list, e.g. :contact-form. I pass that as an input signal to a subscription that gets a specific field from the form, say :first-name. And lastly, I pass that as an input signal to a subscription that returns an error message if the field is blank. That’s a bit oversimplified, but you get the idea.

manutter5113:07:26

If I add debugging statements to print out each subscription as it runs, I see this pattern consistently:

Getting error message from field
Getting form from forms
Getting field from forms

manutter5113:07:28

If I make changes to the field, the error message subscription receives the value as it was prior to my changes to the field. The other subscriptions receive the up-to-date value.

manutter5113:07:44

Does that surprise anyone else as much as it surprises me?

kennytilton14:07:43

Sounds like a “glitch”. btw, I enjoyed hearing that intricate dataflow described as “oversimplified”. 🙂

kennytilton14:07:57

More seriously, I am surprised since I have seen the signal graph described as de-duplicated (not sure on the term) which maes me think this sort of thing would be well worked out. Lemme consult The Google.

kennytilton14:07:45

fwiw, I asked over on #reagent if propagation was glitch-free and never heard back.

mikethompson14:07:44

@manutter51 perhaps re-frame-10x might help?

kennytilton14:07:58

If it were a glitch, btw, you would see “getting error message” twice, once with an obsolete value but then again when the data flow propagation “catches up”.

manutter5114:07:53

Yes, this is reproducible across a co-worker checking in his code and me checking it out and running it on my machine, having never run it before, and with me selecting “Empty Cache and Hard Reload” in Chrome while reloading

manutter5115:07:44

@mikethompson I’m looking at 10x, but the Subs tab is a bit odd, it’s showing a different order of execution than my println’s are showing

manutter5115:07:15

This is using older code that creates subscriptions and passes them to the child; I’m about to do a refactor to standardize on just passing the subscription vectors and letting each component manage its own subs

manutter5115:07:32

I just wondered if this were something anybody had seen before

kennytilton15:07:26

I am trying to remember some hack required to get async console output manageable, but not even sure it was CLJS.

kennytilton15:07:45

You said “co-worker” so I am guessing this is not O/S. I have been thinking about blogging on reactive systems and this is the kind of thing I would be tearing into. I know it is hours of work, but can this be distilled into a shareable 30-40 lines?

kennytilton15:07:40

Also, I joked about it being oversimplified, but that is probably where the problem lies. If what you meant was that other subscriptions were involved, then there could be multiple paths leading from the original change to the “error message” computation. Glitches arise when a signal follows a shorter path bypassing other paths on which “error message” depends.

manutter5115:07:15

Well, there’s not really multiple paths involved, it’s just straight A -> B -> C -> D.

manutter5115:07:34

If I didn’t want the subscription “magic” to happen, it would just be (get-in db [:forms :contact-form :first-name :value]) (plus the code to check the value for errors).

kennytilton15:07:24

btw, what order did the Subs tab show? If it was what you suspected it should be, your logging (or 10x’s) is suspect.

manutter5115:07:31

It showed the subs firing in the order I would have suspected

manutter5115:07:35

er, expected

manutter5115:07:11

The logging is just println’s though, is that not reliable?

kennytilton15:07:31

I think we are on to something. 🙂 Lemme refresh my memory on the unreliable console issue… mind you, you are seeing old data in the error message sub, but then that could be from something else….I love this game!

manutter5115:07:31

Yeah, no that’s a problem with threads; JS is single-threaded

kennytilton15:07:53

Somewhere else I saw a suggestion to call (flush) after every println. Again, clojure was the context.

manutter5115:07:12

Yeah, I don’t think flush is implemented in cljs

kennytilton15:07:59

I know JS is single-threaded, I just like touching all the bases. But I think because you are indeed seeing old data we can concentrate on that and trust the console.

kennytilton16:07:46

hang on. requestAnimationFrame is involved…

kennytilton16:07:17

`Reagent re-runs reactions (re-computations) via requestAnimationFrame. So a re-computation happens about 16ms after an input Signals change is detected, or after the current thread of processing finishes, whichever is the greater. So if you are in a bREPL and you run the lines of code above one after the other too quickly, you might not see the re-computation done immediately after n gets reset!, because the next animationFrame hasn't run (yet). But you could add a (reagent.core/flush) after the reset! to force re-computation to happen straight away.
`

manutter5117:07:54

Yeah, but I don’t think that applies in this case does it? Since the prn is inside the re-computation, we know that we’re already past the point where any delay in starting the recomputation might occur

kennytilton17:07:16

Your problematic recomputation is running before the one (field) that would have provided the current value. I note, btw, that form does run before field, so that’s OK.

manutter5117:07:08

It was, it’s not doing so any more.

manutter5116:07:07

Well, I did find a misspelled key in my data, and I fixed that, and now I’m not seeing the out-of-order subscription values :table-flip: Maybe I’ll just take the rest of the day off now.

🍺 4
Tony21:07:47

Not sure if there might be more interest, or constructive redirection!, in this observer handler type I'm partway through creating. It is basically doing what reg-sub-raw does, but going into a special seq so that a component can opt-in to subscribe to all observers to get them to be triggered. I've included a basic motivating example to demonstrate the type of business logic we have enjoyed moving to these observers and cleaning up our code base. Would appreciate any feedback if there is a better pattern out there or a more idiomatic way to do this in re-frame. https://github.com/lumanu/re-frame-observers