tc39 / proposal-observable

Observables for ECMAScript
https://tc39.github.io/proposal-observable/
3.08k stars 90 forks source link

Subscribe callback with current value of stateful observables #190

Open brianmhunt opened 6 years ago

brianmhunt commented 6 years ago

It's not clear (and perhaps not defined) what should happen when stateful observables like those in Knockout and mobx and others should do when .subscribe is called.

I.e. what should happen in this sequence:

>>> const x = ko.observable('abc')
>>> x.subscribe({ next: console.log })
>>> x('def')

Should the output be abc def or just def?

I ask in particular because I'm adding TC39 support to Knockout.

benjamingr commented 6 years ago

I would expect x to emit abc synchronously and then emit def when the value changed.

brianmhunt commented 6 years ago

Thanks. That's my expectation too. I'd like to be compliant with any specs, or at least consistent with other libraries.

benjamingr commented 6 years ago

@brianmhunt we've (I've) been dragging our feet with this for ~2 years with MobX - I think we can agree on that semantic for it. cc @mweststrate

mweststrate commented 6 years ago

I would expect only def to be emitted, as, imho, you subscribe to the event of a new value to become available, and it is nice that that internal value of the observable doesn't have to be materialized immediately (for example if it is computed). Similar to how attaching in mouse move event doesn't immediate propagate with the current coordinates, however convenient that could be

That being said, personally I don't care that much, as long as it is standardized :-D.

brianmhunt commented 6 years ago

The subscription could provide an option e.g. something like this:

obs.subscribe({
  next: () => ...
  emitCurrentState: true
})
benjamingr commented 6 years ago

@mweststrate I think this is similar to a computed running the function once to know dependents etc.

brianmhunt commented 6 years ago

@mbest any thoughts on this?

mbest commented 6 years ago

I think it should mirror the Knockout subscribe behavior, which is to only emit new changes after the subscribe call. That being said, it's often useful to have a subscribe-type interface that also processes the current value. That's of course how ko.computed works.

appsforartists commented 6 years ago

This feels off-topic to me. The Observable pattern and how Knockout makes use of it are separate topics, and only the former is germane here.

It's common for stateful Observables (e.g. Subjects) to emit the last known value to new subscribers. However, that's a decision to be made at the producer level (probably Knockout in this case), not one that needs to be discussed here.

benjamingr commented 6 years ago

not one that needs to be discussed here.

I don't understand where this is coming from - using Symbol.observable for interoperability between consumers of the API is worth while. You have two libraries with hundreds of thousands of users debating how the language feature proposed should work for them and are asking for clarifications on how to use that feature.

To be honest - as far as I'm aware following this repo for 3+ years we never had this discussion about Symbol.observable yet. I wish more people weighed in to be honest.

I will defer to Jafar and Mark about whether or not they consider this discussion useful at the moment though.

brianmhunt commented 6 years ago

For the moment, in tko/knockout 4 alpha I've set up ko observables to emit their current state whenever a TC39-compliant subscribe call is made (i.e. an object with a next method).

I can be persuaded to change this, particularly before we end the alpha stage, but I wanted to the concept merged — even if not in its final form.

dy commented 4 years ago

@brianmhunt what if initial state is undefined? Does that still emit value?

benjamingr commented 4 years ago

@dy undefined is still a value, so I would expect it to be have the same as any other value.

dy commented 4 years ago

@brianmhunt I meant what if initial value is not defined, ie. value is not provided for init? That is different from undefined, I'd expect observable not to emit sync value, although that inconsistent with regular subscribe.

brianmhunt commented 4 years ago

@dy You mean if the value of the observable had never been set?

I think the behaviour most would expect is to emit an undefined value. Is there a compelling use case for a different behaviour?

dy commented 2 years ago

I remember using that somehow implementing combined observables, not relevant anymore. Note also that simpler signature for subscribe is also possible: obs.subscribe(onnext, onerr?, oncomplete?). Just curious - what's the status?