observable icon indicating copy to clipboard operation
observable copied to clipboard

Promises are inferior to observables for `.every` because the result may be known synchronously but is not readable synchronously

Open rbalicki2 opened this issue 8 months ago • 1 comments
trafficstars

Promise-returning APIs are strictly inferior to observable-returning APIs

A promise cannot be synchronously read. An observable can synchronously fire events. So it's quite unfortunate that you will be unable to read the value of .every (et al) immediately, even if the value is known to be false:

const myObservable = new Observable(subscriber => subscriber.next(123))
myObservable.every(x => x !== 42).then(() => console.log('then callback'))

// yes, this isn't equivalent. I'm being quite lazy
let hasFired = false;
myObservable.subscribe({ next: x => if (x !== 42 && !hasFired) { hasFired = true; console.log('subscribe callback') } })

subscribe callback will be logged during the same tick, and then callback subsequently. This seems like a huge disincentive to using the promise-returning methods like .every, and a strong incentive to use the superior userland variant.

Is this a real-world concern?

  • This pattern (synchronously reading the result of an observable) is used in Relay, and I'm sure elsewhere.
  • In React, if you are reading data from a promise that has already resolved, you have to: throw (i.e. interrupt rendering), store the promise value elsewhere where it can be read synchronously, and re-render. That's a lot! Instead, if one used an observable, one could read the value synchronously and avoid that overhead.

An alternative

If the fact that observables are meant to be able to serve more than one event a reason to use a less performant API, I would suggest introducing a new class (OneShotObservable?) which will call next at most once, and can call it synchronously.

rbalicki2 avatar Feb 28 '25 02:02 rbalicki2

There's some overlap with #20.

rbalicki2 avatar Feb 28 '25 02:02 rbalicki2