WICG / observable

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

Other API ideas: timeouts, Intervals, animation loops #173

Open benlesh opened 3 weeks ago

benlesh commented 3 weeks ago

Just for discussion about another possible use case for observable

One thing that observables get used for frequently is for timing and animations. The APIs available are fine, but they're mildly cumbersome to use.

If, for example, we had an observable that did what setInterval does, it would make intervals a lot more portable and usable in reactive chains, as well as easier to clear in a unified way, because of the use of AbortSignal:

interval(1000).subscribe(console.log)

Which means this would work:

for await (const ts of interval(1000)) {
  console.log(ts);
}

And it could be used to delay things in chains like so:

// Add a 1000ms delay to each value.
source.flatMap(value => interval(1000).take(1).flatMap(() => [n]))
  .subscribe(console.log);

What it would provide is honestly debatable. RxJS provides an incrementing number, but IMO, that's sort of arbitrary. We might provide something like what requestAnimationFrame does, which is a high resolution timestamp.

requestAnimationFrame is another API that is used a lot, although in a recursive way, in observables. Usually people make animation loops like so:

let id = 0;

const run = (ts) => {
  console.log(`timestamp: ${ts}`);

  // Do some animation work

  // start another run
  id = requestAnimationFrame(run)
}

function start() {
  id = requestAnimationFrame(run);
}

function stop() {
  cancelAnimationFrame(id);
}

But with an observable API it could look like something like what I've written below. The RxJS version of this also provides elapsed time along with the timestamp, but that's probably not necessary, it's just really useful when animating things.

const ac = new AbortController();

animationFrames.subscribe((ts) => {
  console.log(`timestamp: ${ts}`);

  // Do some animation work
}, { signal: ac.signal });

// stop the animation later
ac.abort();

Unrelated: I've long wanted a timeout(ms, { signal }) API that returns a Promise, but interval(ms).first({ signal }) will suffice.

bakkot commented 3 weeks ago

Unrelated: I've long wanted a timeout(ms, { signal }) API that returns a Promise

Me too. Last I checked this is proposed as part of the scheduler API as scheduler.wait, which seems like very much the wrong place for it to me, but browsers are unlikely to want to duplicate such any API anywhere else if it does land there.

I see that proposal mentions possible future integration with Observable, actually.

domfarolino commented 3 weeks ago

How much of this is captured by https://github.com/WICG/observable/issues/72?

esprehn commented 16 hours ago

I left my comments on https://github.com/WICG/observable/issues/72#issuecomment-2359379069