w3ctag / design-reviews

W3C specs and API reviews
Creative Commons Zero v1.0 Universal
318 stars 55 forks source link

Observable API #902

Open domfarolino opened 9 months ago

domfarolino commented 9 months ago

こんにちは TAG-さん!

I'm requesting a TAG review of Observables.

This proposal adds an .on() method to EventTarget that becomes a better addEventListener(); specifically it returns a new Observable that adds a new event listener to the target when its subscribe() method is called. The Observable calls the subscriber's next() handler with each event.

Observables turn event handling, filtering, and termination, into an explicit, declarative flow that's easier to understand and compose than today's imperative version, which often requires nested calls to addEventListener() and hard-to-follow callback chains.

Further details:

We'd prefer the TAG provide feedback as:

💬 leave review feedback as a comment in this issue and @-notify @domfarolino and @benlesh

artalar commented 6 months ago

Hi! One more opinion: https://dev.to/artalar/my-criticism-about-the-new-observables-api-37d5

People in my bubble have had a bad experience with observables (especially with merging a few streams) and are scared of the API and the complexity that it could bring to the platform.

benlesh commented 6 months ago
  • It would introduce another way to accomplish the same thing, which would confuse beginners and make the platform more complex. We already have callbacks, promises, async/await, events, streams, and generators.

Observables are another way to accomplish a lot more than what current methods allow. So "sort of". Callbacks exist in everything else you listed. promises and async await are firmly different concepts and ECMAScript features, not related the DDOM. Events aren't really a construct, but rather something that can be handled by the other things you listed. Generators are wildly different than Observables, they're pull-based where observables are push-based. Async Generators are pull-then-push, and slightly more complicated than observables. Especially when you start talking about coroutines.

  • There will always be a shortage of operators. Definitely check out rxjs.dev/api.

IMO, as the lead maintainer of the library, RxJS has too many operators, and we've been deprecating and removing them over the years.

  • We are uncertain about how it should work. The popular observables library RxJS is constantly improving and changing. Its internal logic and codebase are not simple. So, why do we assume that the current proposed API will be sufficient for us in the future?

I'm very sorry, this part is just plainly false. We haven't added any new operators in years. We've removed a few operators, and a lot of the work that is going into RxJS over the last few years is aimed at simplifying the codebase. In general, outside of "pipeable" operators, RxJS has barely changed in the 10+ years of its existence.

The only thing that's really been evolving over this time period is the growing user base of the library. Despite not being funded by any major tech company. Despite not having a dedicated staff, and only being maintained by volunteers. Despite not having an advertising budget, people are choosing RxJS to help them manage coordinating events. And it's not just RxJS. If you checkout the README for the proposal, there are several wildly used projects employing an observable type in their codebase.

LeaVerou commented 4 months ago

Hi everyone, apologies for the delay @domfarolino.

We discussed this in a breakout today, though we ran out of time before reaching a conclusion. The following are some personal thoughts and comments.

First, the author pain points are clear, so motivation is pretty obvious.

My main concern is the standardization venue. It seems very clear that ES will eventually need an Observable primitive and we would not want the web platform to have another conflicting primitive. Also, when it comes to pure JS language features, TC39 is the clear fit for this. The fact that AbortSignal/AbortController were not standardized in TC39 is unfortunate, and shows in their ergonomics — I think it's important to avoid this pattern. You mention that Observable does to Events what Promises did to callbacks, but one of the reasons Promises were so successful is exactly that they were specced as a language feature.

Looking at https://github.com/tc39/proposal-observable/issues/201#issuecomment-1021145957 it appears that the primary issue stems exactly from AbortSignal / AbortController. FWIW although we generally recommend against monkey-patching, I think it would be the lesser of two evils to have the Observable API specced by TC39, and only a signal parameter elsewhere, than to have the entire Observable API specced by WHATWG or another browser-centric venue.

Another concern is that it seems that this still depends on the EventTarget infrastructure, and basically provides a wrapper over it with better DX. But if we go through the effort of creating a completely new API, it seems like it should not come with EventTarget baggage, an API that was designed for the DOM and later retrofitted to other objects. E.g. as a library author, I find it unfortunate that for my objects to support events that my users can listen to I need to make them inherit from EventTarget (and since we don't have multiple inheritance, this precludes them inheriting from anywhere else).

Stepping even further back, we have way too many different pub/sub patterns on the Web platform and DX suffers as a result. To an author it is unclear why we have an Events system and e.g. MutationObserver, ResizeObserver, etc. I understand the reasons, no need to explain them to me, I’m just saying most authors don't and from a UI perspective, it's an implementation detail that has leaked out into the UI because the DOM Events infrastructure did not support this use case well. For a new pub/sub pattern to win them all, we really need something that would be able to support all of these cases, and be used as the underlying model for all of them (i.e. DOM Events can become a special case of Observable, same with MutationObservers etc).

Lastly, as a more minor point than the architectural concerns above: is there 1-1 parity with what addEventListener can do? E.g. by looking at the API I could not figure out how to do an once event listener.

Also props for a nice explainer, and especially for having code examples! I also loved that some code examples had a collapsed version with how this is done currently — wish all of them had this!

LeaVerou commented 1 week ago

Hi @domfarolino,

We looked at this today during a breakout. We do have consensus on most of the concerns I expressed above, especially around standards venue.

Furthermore, we had some questions about the API shape that we couldn’t figure out from the explainer, and we were hoping you might be able to clarify.

It seems (though we are not 100% certain) that this is a separate primitive than EventTarget and simply integrates with it. If that is correct, the current explainer is a little unclear on what the boundaries of each are. Does it use the same Event objects? Does it register event listeners behind the scenes? How does bubbling work? Does it support bubbling to parent objects when not using the EventTarget integration?

We think a reworking of the explainer would really help answer these types of questions. Some (non-exhaustive) suggestions:


@littledan @ljharb @ctcpip @robpalme We saw you folks upvoted my last comment. Has there been any recent discussion in TC39 around this? Any plans to discuss it in the upcoming Plenary?

ljharb commented 1 week ago

@LeaVerou I've been suggesting to @domfarolino ever since I became aware of the browser effort that TC39 would be a better venue, but there's not been much discussion in plenary about it, since imo unless Chrome is willing to wait for the language to add Observables, our hands are kind of tied.

robpalme commented 1 week ago

TC39 is available as a venue with no special strings attached.

@domfarolino I believe you already belong to an Ecma member company (Google) so it will be trivial for your lead delegate (Shu) to onboard you as a TC39 delegate. Discussion can happen at any time in Matrix or in adhoc meetings organised on the Reflector. And you would be welcome to schedule the item for formal discussion in the next meeting which is July.

littledan commented 1 week ago

One key reason why it would be difficult to do Observables in TC39 is its use of AbortSignal as an unsubscription mechanism--which is a good API pattern in alignment with the rest of the web platform. There are other features under discussion in TC39 which may benefit from this notion of cancellation, e.g,. Signals. I see multiple ways we can work this problem out layering-wise, given some more explicit collaboration between TC39 and WHATWG. I have recently raised this AbortSignal layering topic to TC39, and have started chatting with some people within WHATWG about it; I hope to follow up in the coming months with a more clear proposal (but if someone wants to take a stab at this sooner, feel free).

I'd suggest bringing Observables to discussion in TC39 simply for a review of its current shape, focusing mostly on what the feature is for and how it serves developers, rather than focusing on its venue. In particular, I want to make sure that there's a strong, shared understanding of the relationship between Observables and Signals (they are complementary in their use cases, and we should have a well-understood, shared story around them, even if they're standardized in different venues).