3 ms·
Agreed, thats why there are proposals of introducing Observables as ES8 native datatypes. Note that while full RxJS is heavy, Observables are not. Its the multi
by littlecranky67 9y ago
Agreed, thats why there are proposals of introducing Observables as ES8 native datatypes. Note that while full RxJS is heavy, Observables are not. Its the multitude of operators to compose observables, and the various helper implementations of Subjects (AsyncSubject, ReplaySubject, BehaviorSubject etc.) - which are similar to Defereds in Promise world - that make RxJS so heavy. If you use only the Observable part with a slim selection of operators in your code, you will not add so much of the library to your code (but granted the patch-based API of RxJS is not really trivial).
- Mitranim 9y agoI believe we need a hierarchy of primitives: Level 0: one-value operations (promises = futures). Level 1: multi-value operations (streams = observables), implemented in terms of one-value operations. Tokio did it well for Rust (https://tokio.rs https://tokio.rs). Starting at level 1 doesn't feel right to me.
- littlecranky67 9y agoI'd rather have a clear separation of data structures and implemenations: Promise, Future, Observable = data structures Bluebird, Fluture, RxJS Observable = implementation of the data structures Operators (map/race/all) = helper implementations for operating the data structure implementations Now, different implementations may make different choices, like there are dozens of Promise implementations tuned for either feature richness, speed, or small file size. Same holds true for observables, there are feature-rich libs like RxJS, but also fast and/or small implementations (Bacon, most.js, xstream). My point: A cancelable promise is basically an observable that emits a single item (and caches that item). So an observable is kind of like a superset of a cancelable promise (and of course a non-cancelable promise). All operator implementations manipulating observables can directly be reused for cancelable and non cancelable promises-like observables; the other way around does NOT hold true. My main point: Just use observables, they can do everything that promises and cancelable promises can do and, if needed, a lot more. So instead of layering, learn to use this one data structure and you will be able to cope with a lot of async troubles.
- shados 9y agoThe main point is correct. But observables are very different from promises at the core. Not only are they cached, but they're also eagers, while observables are not. The very minimum implementation of an observable is just a few lines of code. Promises...are much more complex. So I'm not sure how reusing operators between the two efficiently would work. So yeah, just use observables. Most people think observables are a more complex, higher level abstraction with promises being the primitive, simple one. It isn't true though. Observables are much, MUCH simpler, and are perfectly suited to doing everything promises do, but better (lazy, optionally cached async primitive is way better).
- littlecranky67 9y agoYou can make any observable "cached" in RxJS by subscribing it to a ReplaySubject or by calling .publishReplay(N).refCount() on them. So observables can be cached or uncached, and the cache length can be specified (N parameter). They can also be eager or lazy; that is the hot/cold lingo in RxJS world (or unicast/multicast). I repeat my claim: Observables (at least as implemented by RxJS) are a superset of (cancelable-)promises. Superset means, they can do everything the exact same way as promises, and a lot more.
- Mitranim 9y agoNo disagreement here. Rx observables are strictly more powerful than promises/futures/streams. But why start with the superset? I don't think it's good design. Consider the perspective of a language designer. You want to start with primitives that are as simple as possible while satisfying a vast number of real use cases. One-short async primitives are an important intermediary step towards observables, it shouldn't be skipped. Observables should be implemented in terms of these. This layered design gets you a smaller cognitive cost of entry (promises are hard enough as it is!) and higher efficiency for the vast number of cases that don't need stream-like functionality. On top of that, one-shot primitives are conceptually compatible with blocking expressions in coroutines such as async/await, whereas streams are not. I don't get it when people shoot for fat primitives that do it all.