As far as I understand, following are the techniques to solve asynchronous programming workflows:
Newer approaches:
We are now moving away from callbacks & promises to these newer approaches. What I understand currently is - Async/Await is more like a cleaner abstraction on top of ES2015 generators.
What I am not able to understand is the conceptual difference between Observables and Generators. I have used both extensively and have no trouble in using them.
What confuses me is the use case for Observables and Generators. I have come to conclusion that, in the end, they are addressing the same problem - asynchronicity. Only potential difference I see is generators inherently provide imperative semantics to code while Observables using Rxjs seem to provide reactive paradigm. But is that it?
Should that be the criteria to choose between Observable and Generator? What are the pros and cons.
Am I missing the big picture?
Also with Observable eventually making into future Ecmascript, are Promises (with cancelable-token)/Observable/Generators going to compete with each other?
Observable uses generators to represent values that change over time. Generators enable interaction, animation, realtime data streaming, and all the other exciting, dynamic capabilities of Observable notebooks. The simplest generator is a cell that yields a single value.
RxJS (Reactive Extensions for JavaScript) is a library for reactive programming using observables that makes it easier to compose asynchronous or callback-based code.
Observable JavaScript represents a progressive way of handling events, async the activity, and multiple values in JavaScript. These observables are just the functions that throw values and Objects known as observers subscribe to such values that define the callback functions such as error(), next() and complete().
Observables push changes, and hence the observable, not the function reacting to it, is in control. Generators on the other hand require you to pull values out of them. So the function that will react to the new value determines when it is ready for a new value.
I had trouble with backpressure using observables, but with generators, you can let values out as slowly as you want.
Edit: the last question. Promises are just observables that only emit once, so I don't think they will compete with each other. I think the real battle will be async/await vs observables, and async/await has a head start, and is already in C# (and now Node.js). But observables have that sweet FRP feel, and functional programing is super cool, so I think they will both end up with a good chunk of mindshare.
Edit2: André Staltz, author of Cycle.js and xstream, and contributor to Rx.js, wrote a great article on how generators and Observables relate (on 2018-01-31). In particular, he shows how they both inherit from a common base class.
And now a consumer can be a Listener (“observer”) or a Puller, it’s up to the consumer whether it will pull the producer or not. And the producer can be a Listenable (“observable”) or a Pullable (“iterable”), it’s up to the producer whether it sends data proactively or only on demand. As you can see, both consumer and producer are simple functions of the same type:
(num, payload) => void
So any operator that we build will work for both reactive programming or iterable programming, simply because the line between those two modes gets blurred and it’s not anymore about observables versus iterables, it’s just about transformations of data between producer and consumer.
I recommend reading it [link]. The article introduces "Callbags", a spec for callbacks used for reactive and iterable programming. He implements that spec to make a tiny library for both iterable and reactive programming. To entice you to read the article and check out the library, here are some examples from the 7kb lib based on the spec he introduces:
Reactive programming example
Pick the first 5 odd numbers from a clock that ticks every second, then start observing them:
const {forEach, interval, map, filter, take, pipe} = require('callbag-basics'); pipe( interval(1000), map(x => x + 1), filter(x => x % 2), take(5), forEach(x => console.log(x)) ); // 1 // 3 // 5 // 7 // 9
Iterable programming example
From a range of numbers, pick 5 of them and divide them by 4, then start pulling those one by one:
const {forEach, fromIter, take, map, pipe} = require('callbag-basics'); function* range(from, to) { let i = from; while (i <= to) { yield i; i++; } } pipe( fromIter(range(40, 99)), // 40, 41, 42, 43, 44, 45, 46, ... take(5), // 40, 41, 42, 43, 44 map(x => x / 4), // 10, 10.25, 10.5, 10.75, 11 forEach(x => console.log(x)) ); // 10 // 10.25 // 10.5 // 10.75 // 11
You can consider the rxjs observables as asynchronous generators i.e. generators yielding promises. Just because the content is not guaranteed to be ready at the time we call .next (in opposition to regular generators)
More reading
asynchronous Iterators proposal
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With