⬆️ ⬇️

Joining Reactive Programming that you missed

Well, you decided to learn a new thing called Reactive Programming, and in particular its implementation in the form of Rx, Bacon.js, RAC or something else.



Training is a complex process that becomes even more difficult when there is no suitable material. And at the beginning of my training, I tried to find some tutorials. But all that I found were partial guides that were superficial in nature and did not give a holistic view of the construction of architecture. And the documentation on the libraries did not really help with the understanding of some functions:

Rx.Observable.prototype.flatMapLatest (selector, [thisArg])



There are no changes in the sequence of observable sequences into the sequence of observable sequences.


Holy cow!

')

I read two books, the first of which just described the big picture, while the second described the use of a particular library. The end of learning reactive programming was difficult - I had to deal with him in the process. In Futurice, I applied it in a real project with the support of some of my colleagues .



The most difficult part of the learning process turned out to be to teach your brain to work in a “reactive” style, having old imperative habits and persistent design patterns. Unfortunately, I did not find lessons on the Internet that would describe this aspect, and I thought that the world deserves a few words about how to think in a reactive style. In general, we can begin. And the documentation of the libraries can help to continue the flight after my article. I hope that I will help you.



What is Reactive Programming?





There are many bad explanations and definitions of reactive programming on the Internet. For example, Wikipedia, as always, summarizes and theorizes everything, and Stackoverflow contains canonical answers that are not suitable for a beginner. Reactive Manifesto sounds like one of those things that you need to show your project manager or business analyst of your company. And Rx terminology “Rx = Observables + LINQ + Schedulers” is so heavy and microsoft that most of us can only resent. Slogans like “reactive” and “propagation of changes” do not explain anything concrete, which distinguishes the typical MV * approach that is already embedded in your language. Of course, the views from my framework respond to models. Of course the spread of change. If it were not so, we would not see the work of the program.



Well, let's dot the i.



Reactive programming is programming with asynchronous streams of data.



In general, there is nothing new here. Event buses or typical button press events are all real examples of asynchronous event streams that you can listen to and perform some side effects. In fact, reactivity exploits this idea on steroids. You are given the opportunity to create streams of something, not just click events. The streams are lightweight and used everywhere: variables, user input, properties, cache, data structures, and much more. For example, a tweeter tape can be a stream of data along with a series of user interface events. That is, you can listen to the stream and respond to events in it.



Moreover, you get a wonderful set of combination tools and functions that allow you to create and filter each of these streams. This is where "functional" magic makes itself felt. Streams can be used as input parameters to each other. Even a multiple stream can be used as an input argument to another stream. You can combine multiple threads. You can filter one stream, then get another, which contains only actual data. You can combine data from one stream with data from another to get another one.



So, if the flows are the central idea of ​​Reactivity, let's take a closer look at them, let's start with the “pushing a button” event flow that is familiar to us.

image

A stream is a sequence of constant events sorted by time . It can contain three types of messages: values ​​(data of a certain type), errors, and a shutdown signal. Consider the fact that a completion signal occurs for an instance of an object while pressing the close button.



We receive these generated events asynchronously, always. According to the ideology of reactive programming, there are three types of functions: those that must be performed when some specific data is sent, error handling functions, and other functions with signals that the program has terminated. Sometimes the last two points can be omitted and will focus on defining functions for processing values. To listen (listening) to a stream means to subscribe to it. That is, the functions that we defined are observers. And the flow is the subject that is being watched. This approach is called Observer Design Pattern.



An alternative way to present the above diagram is the ASCII graphic, which we will use in some sections of this tutorial:
--a---bc---d---X---|-> a, b, c, d are emitted values X is an error | is the 'completed' signal ---> is the timeline 






In order not to let you get bored, let's analyze something new, for example, create a stream of events, transforming the initial stream of click events.



The first thing we will do is add a counter, which will be an indicator of button presses. In most Reactive Libraries, each thread has many built-in functions, such as merge, filter, scanner, and so on. When you call one of these functions, such as clickStream.map (f), it returns a new stream , which is based on the parent (clickStream). A child thread does not in any way affect or modify its parent. This property is called immutability and is an integral part of the reactive flows, as well as pancakes cannot be imagined without syrup. This allows us to combine functions (for example, clickStream.map (f) .scan (g)):

 clickStream: ---c----c--c----c------c--> vvvvv map(c becomes 1) vvvv ---1----1--1----1------1--> vvvvvvvvv scan(+) vvvvvvvvv counterStream: ---1----2--3----4------5--> 


The map (f) function creates a new stream in which each new event is replaced with the f function. In our case, we bind the unit to each click on the button. The scan (g) function aggregates all previous values ​​in the stream, returning the value x = g (accumulated, current). After that, counterStream sends the total number of clicks.



In order to show the real power of the Reactive approach, let's just say that you want to get a thread that will cause a double tap. In order to make everything more interesting, let's say that we want the new thread to consider triple clicks as double, or, in general, as multi-pressing (two or more). Take a deep breath and imagine that you could do the same in the traditional imperative manner. I bet it sounds pretty ugly and includes variables for saving certain states and time intervals.



That is, in Reactive programming, everything is very simple. In fact, the logic is concentrated in 4 lines of code

. But let's not pay attention to the code, for now. Meditating on a diagram is the best way to understand and build flows, no matter whether you are an expert or just starting.

image



Gray rectangles are functions of transforming one stream into another. The first thing we did was accumulate clicks on the list. Whenever a delay of 250 milliseconds passes the event (that's why buffer (stream.throttle (250ms)), an event is generated. Don't worry about understanding the details of this moment. We just deal with Reactivity. The result is a list stream where each element has been applied the map () function to add its length to each list. Finally, we ignore the number 1 using the filter function (x> = 2). That's all - only 3 operations to create our target stream. We can subscribe to it listener that will respond exactly as to we want.



I hope you enjoyed the beauty of this approach. This example is just the tip of the iceberg: you can apply the same operations to different types of data streams, such as API response streams. And besides, there is still a huge number of other functions ahead.

Source: https://habr.com/ru/post/279715/



All Articles