Git Product home page Git Product logo

Comments (2)

yurique avatar yurique commented on August 20, 2024 1

I don't remember having problems related to this, either.
But I'm usually only using .fromValue(..) to "pre-start" some other stream of events (like in EventStream.merge( fromValue( ... ), buttonClicksStream )).

from airstream.

raquo avatar raquo commented on August 20, 2024

I think I fixed this. The fix is pretty simple, but I had to arrive at it the hard way, after trying out increasingly complicated mechanisms that did not work.

The suffering

Initially I was operating under an assumption that I want or need to fire events that are emitted onStart by all of the streams listed in the Scope section in a shared transaction, similarly to how we handle events emitted onStart by signal.changes. This turned out to be both undesirable and seemingly impossible to get right.

It's hard to get right due to weird cases like EventStrean.fromSeq that emit multiple events onStart. The second and subsequent events can not be emitted in the shared transaction, because an observable can only emit once in any given transaction. However, I wasn't able to figure out how to schedule the execution of those subsequent transactions in a universally desirable and predictable order. Interactions with other features like flattening, and SyncObservable-s make me think that this is in fact not possible to do safely in the general sense, and that fromSeq could be only a private case of a bigger, problem that is unsolvable in principle, for the same reasons that we need transactions in the first place.

But this is all moot, because the behaviour I was trying to achieve is actually undesirable. I realized that signal.changes is different from all other streams in a rather fundamental way – its output does not create events from thin air, it gets them from a parent observable, and does not normally create its own transactions. All other streams in the Scope list are the opposite – they create their own events [1], and always fire them in new transactions. Because of that, there is no reason to shove all those events (that are normally fired in separate transactions) into one shared transaction – all we need to do is to delay the execution of those transactions until the Transaction.onStart.shared callback is finished, i.e. (in practical terms as it relates to this ticket's stated problem) until all subscribers have been added.

[1] Except the flatten ones, I will have to think about those again.

The actual solution

So, that's what I did. Now, any transaction created inside Transaction.onStart.shared is added to a separate postStartTransactions queue. After everything else is done, but before the shared block relinquishes control, each of those transactions is scheduled for execution after the current (shared) transaction, in the same order.

I also fixed a bug where multiple signal.changes would fire in the wrong order in the shared onStart transaction under certain conditions, and a bug where signal.changes wouldn't fire at all on start (not sure if that one was possible to encounter with typical Laminar usage, but it was possible in manual Airstream usage).

Try it out

I published Airstream 17.0.0-M1 with this fix. It should be binary compatible with Laminar & Airstream 16.0.0. If you are using Laminar 16.0.0, please add "com.raquo" %%% "airstream" % "17.0.0-M1" to your dependencies, and see if anything breaks (primary scope: elements with streams mentioned in Scope getting mounted). Everything should work fine, unless you're implicitly relying on this bug, which is unlikely.

That said, there could be slight differences in the order of events fired when mounting elements. For example, now signal.changes will emit before all other transactions such as EventStream.fromSeq, whereas previously it would depend on their relative order. (Remember, this is only when starting / re-starting multiple observables at the same time, e.g. when mounting an element that contains several subscriptions).

If you try it out, please subscribe to this issue to get notified of any problems reported by other users.

from airstream.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.