Hacker News new | comments | show | ask | jobs | submit login
RxFiddle: Visualize your Observables (rxfiddle.net)
50 points by pbadenski 9 months ago | hide | past | web | favorite | 16 comments

I've found RxViz: http://rxviz.com/ to be super useful as well!

Very cool. I’ll have to try this out the next time I have trouble with a RxSwift observable chain.

One of the nicer sides of using Rx is that converting from one implementation to the next is usually fairly trivial.

Yes indeed cool. Find this useful as an Angular dev.

Honestly, I don't get it. What's the benefit here to having this library as opposed to just calling those functions directly when some data in object changes?

I guess you could argue if you had tons of data, but I wouldn't be using a frontend application to implement a distributed queue processing and messaging system...

The two big things are the ability to reason about your logic with a consistent mechanism (asynchronous streams) as well as the very rich set of supported operators for those streams. This allows you to treat asynchronous inputs (AJAX callbacks, I/O, UI events, etc) similarly, which can make gluing the pieces together a lot nicer.

It’s used a lot more on the front end than on the back end, in my experience. But I really enjoy working with it.

RX is a hilarious pattern IMO. 90% of the usage I've seen would be simpler and less code just doing things the old fashioned way.

The vast majority of observer pattern use cases are solved a lot more clearly by using async

Yeah but the pattern emerged before `async/await` was javascript standard so people kind of sticked to it.

I know some not bad js developers who use RX a lot and have no idea about `async/await` existence, I even had to explain to couple of them how `async/await` works and what is "imperative code". No joke.

Why not both? It doesn't have to be either/or: async/await is a great monad for cases where you need a simple imperative flow. Rx and the Observable pattern are great for cases where you have more complex data flows with complex needs like backpressure support (throttling and buffering), and complex time management.

Each has very different strengths, and it's very easy to work with both together.

    const someStream = Rx.fromPromise(myAsyncAwaitFunction())

    const arrayINeed = await myRxObservable.toArray().toPromise()

let val = await Thing();


Observable.of(thing).subsribe((res)=>{call back}

For all(most) cases where you only need to hear back once

If you only need to "hear back once", then yes, Observables are probably overkill.

But again, it's a false dichotomy, and your second example isn't much different from what await essentially rewrites to:

   Thing().then(val => /* call back */)
The benefit to async/await is that the runtime does the rewriting to Promise callbacks for you. But you can use both and get that advantage for both. Rx has supported converting to/from Promises since the beginning. Working with both is easy.

    let val = await observableOfJustOneThingINeed
      .take(1) // I just need one, I don't care if there are more
You don't have to manually subscribe, you can use a Promise and await it.

There are cases as well where maybe you want a linear async/await flow in the middle of an Observable flow, too.

For instance:

    let jsonStream = searchFieldChanges // observable of search field change
        .debounce(300 /* ms */) // don't do it too often
        .flatMapPromise(async (search) => {
            const request = await fetch(`${searchUrl}?query=${search}`)
            return await request.json()
ETA: To reiterate the point: both tools are better together and it's not one or the other, it's like most tools finding the right one for the right job.

What RX gives you is a smooth flow to the last callback. Async is admittedly less flexible but the only way I know of to trigger asynchronous flow without a callback.

I worked in the C# world for a while and I'm still in envy of how clear and powerful good async support is.

Under the hood, async/await is using callbacks into a finite state machine. JS Promise and C# Task<T> (which are very similar in design, for obvious reasons) are both still driving the operations in an async/await function, the JS runtime, C# compiler (or TS compiler), is doing the heavy lifting of converting imperative looking code into a finite state machine for Promise/Task callbacks.

You can't avoid callbacks in an asynchronous flow. async/await is just a conversion between imperative looking code and a callback structure. It's a great win for developers that we've built such conversion tools (thanks to work on monads in languages like Haskell and OCaml).

Rx is for higher-order asynchronous streams where you have multiple events over time. It doesn't have the beauty of async/await because it's a much more complicated abstraction than the basic monad of Promise/Task. If you have a stream of events over time you can use Rx and if you have just one Promise at a time you can use Promise/Task and thus async/await. (The difference between I want to know every click of this button and I want to know just the next click of this button.) Most applications are a little bit of column A and a little bit of column B, and you don't have to pick one or the other, you can use both side-by-side.

Async avoids callbacks by restoring your calling context under the hood just like the compiler does for normal function calls and callbacks. It just does it in a way thats clearer IMO

For me, it's just another way of thinking about change. Even when a value changes over time, it is possible to capture or model an immutable truth about it: the relationships that determine each new value.

Are you asking about using RX itself? You don't have to maintain any state, its declarative. You could use this on the backend. Its not a queue or a messaging system. Imagine you had to implement a triple click event. RX would be useful for that. Its a way to say "give me all click events that occur within X milliseconds of each other". Or a way to say give me all the mouse drag events that happened after a mouse down but before a mouse up.

Sure you can do it with imperative programming, without RX. You can also filter an array with a for loop instead of using .filter(), but the latter is often more desirable. Just like the array .filter() method, you have to stop & learn something you already maybe know how to do with a loop, but the benefit is writing less code to do it. Heck you don't even need the loop, you could use goto statements to filter an array.... but there are reasons to work at higher abstraction levels.

Another example is an auto-complete, traditionally each key up event / input event would trigger an ajax request, and requests may finish out of order causing race conditions. RXJS has a way (switchMap I think) to declaratively say "give me the results in the correct order", another operator declaratively says only give me the latest event.

This is not new in any way, big companies like Microsoft & Apple have been doing reactive functional programming since like the 70s, I think. Its just new to Javascript is all. Just like other programming paradigms, its also not the answer for everything, just another tool to use. I believe in Angular 4, all http requests return observable now. Vue.js (v3) will also switch from object.defineProperty to observable pattern. GraphQL subscriptions / Apollo Client uses observables....

An observable is like a promise, but nothing executes until you call .subscribe(), so they are lazy. You can describe what will happen in response to an input event, such as making an ajax request, without actually kicking off any ajax requests until those events happen. This isn't possible with a promise, which starts its async action as soon as its defined.

They can be cancelled before you call .subscribe(), and they are multi-valued. They can finish after emitting multiple values, or even a single value. Or they could finish without emitting any values (think like a promise, but with cancellation)

Also like a promise, it makes composing callback based code simpler.

In the auto-complete example, you can think of the program like a stream. Input events get turned into ajax requests which get turned into stuff displayed on the screen. Its a stream, and RXJS is how you setup the plumbing. Then data flows through that stream at run-time, without having to maintain any state. For a lot of use cases, this will result in more confusing code than doing it imperative. For other use cases, it will eliminate a lot of race conditions & create succinct easy to debug code. Its a trade off. The trade off is a higher learning curve, but the benefit is more declarative async code.

For further info I recommend to lookup Ben Lesh on youtube.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact