WICG / observable

Observable API proposal
https://wicg.github.io/observable/
Other
546 stars 12 forks source link

Way for single event subscription? #65

Closed saschanaz closed 2 months ago

saschanaz commented 10 months ago

I think this proposal is mostly for repeated events, but is there corresponding way of once: true in addEventListener?

Something like:

await element.on("click").takeImmediately()
domfarolino commented 10 months ago

Oh, I filed #66 and wrote #67 (which removes once: true from the event listener options that we use) before seeing this by the way. We could keep once in the event listener options, although it seems like your desire is not to use that directly, but instead introduce an operator that more-or-less gives you a Promise for a single Observable event, right? We've discussed adding .toPromise() recently (in contrast with toArray()), which I think offers some pretty explicit language, but also we have .first() currently commented-out in our WebIDL sketch, which I think satisfies this but with less explicit language. How do any of those sound?

My thought is that the .on() method would always create an Observable (over the "add event listener" internals) whose teardown is to remove the event listener. Something like toPromise() or first() would subscribe to the observable, and unsubscribe after the first event (thus removing the event listener like once: true would). Maybe we could just uncomment first() or rename it to toPromise() or takeImmediately()? I might prefer toPromise() to be extra explicit about the scheduling impact.

benlesh commented 9 months ago

One problem with a promise returning API is that you'll have an event in a different async context, where e.preventDefault() is too late.

This can be done like so:

await element.on('click').take(1).forEach(e => {
  // Do what you need do with the even in here.
  // Since this is synchronously dispatched, things like
  // e.preventDefault() can still be used.
});
domfarolino commented 3 months ago

At this point we've decided to add the first() Promise-returning operator (see https://github.com/WICG/observable/pull/131 and https://github.com/WICG/observable/issues/126) which I think satisfies this request, and @benlesh has kindly provided a nice example to keep synchronous scheduling when needing synchronously react to the "first" event (in order to preventDefault() or something like that).

I'll set up https://github.com/WICG/observable/pull/131 to close this issue once merged.