Rxjs has recently been learning, in the process of learning, stepped on a lot of pit, also found that online articles are more or less some problems, either the content out of date (now Rxjs6), come up to speak or principle (let me a face of meng force), or it’s not clear, feel stepped on a lot of pit, the learning curve is relatively steep. After understanding the basic concept and looking back, it is not difficult to understand, but it did take a lot of detours, so sorted out, as workers, as few pits as possible.

Learning the pose

When I was studying, I mainly read official documents. I failed to verify some vague things in time, which resulted in a half-understanding of them. When I encountered actual documents, I had to check them repeatedly.

The best way to do this is to write as you go along. It is highly recommended to create a basic version of the Rxjs template from Stackblitz.com/. The examples below run in this environment.

Pit point warning

  1. Many articles will talk about publish and subscribe, observer model, iterator model and increase learning cost. The key is that in actual learning, always thinking about these two models will bring higher understanding cost. A new gadget, you might not even know how to use it, and you’re trying to understand how it works, and it doesn’t make any sense.

  2. A more common misconception is that Rxjs is just a subscriber pattern like addEventListener, and the method name subscribe is also misleading. When it comes to subscribe, forget about publishing and subscribing in your head, look at the example and understand its essence, don’t worry about the name. This makes me unable to get started for a long time. In fact, at this time, it is the best way to throw away the existing knowledge and learn new knowledge directly.

  3. The documents on the official website mention a lot of difficult concepts, focusing on design ideas, such as pull and push, and trust me, when you actually use them, you can look back at them at a glance, but if you get stuck in them at the beginning, you will be sad, right

  4. Rxjs can be regarded as a loDash library for streams. It is impossible to understand all methods in LoDash at the beginning, so don’t bother with operators. If you encounter them, check them out and understand them

The above is the pit point, in the follow-up study to avoid these pits, can take a lot of detours.

Rxjs introduction

Think of Rxjs as Lodash for events. Think of Rxjs as loDash for Events, that is, Rxjs is essentially a library of tools that handle events. The events here, you can call them flows.

So what does flow mean? For example, the code outputs a number every 1s, and every time the user clicks on an element, it creates a data set in the dimension of time. Unlike an array, this data set does not always exist at the beginning, but is exported one by one over time. The data generated by this asynchronous behavior can be called a stream, which in Rxjs is called an Ovservalbe. Rxjs is a tool created to deal with such flows, such as stream merging, stream truncation, delay, chattering and so on.

Understand basic definitions: Observable, Observer, Subscription

A basic stream can be constructed by printing an array [1,2,3] at 500ms, an object {a: 1000} at 1s, ‘end’ at 3s, and then terminating the stream at 4s.

import { Observable } from "rxjs";

// stream$$indicates that the current variable is ovServable
const stream$ = new Observable(subscriber= > {
  setTimeout(() = > {
    subscriber.next([1.2.3]);
  }, 500);
  setTimeout(() = > {
    subscriber.next({ a: 1000 });
  }, 1000);
  setTimeout(() = > {
    subscriber.next("end");
  }, 3000);
  setTimeout(() = > {
    subscriber.complete();
  }, 4000);
});

/ / start the flow
const subscription = stream$.subscribe({
  complete: () = > console.log("done"),
  next: v= > console.log(v),
  error: () = > console.log("error")});// output
// [1,2,3] // 500ms
// {a:1000} // at 1000ms
// end // at 3000ms
// done // 4000ms
Copy the code

In the above code, we define a stream with new Observalbe(fn), and start the stream with stream$.subscribe(obj). After 500ms, we execute ““subsciber.next([1,2,3]). The value is printed through the obj.next method passed in.

Here are a few points:

  1. Subscribe is not a subscription, we start the stream, and as you can see, after subscribe, we execute the next method
  2. When an Observable is built, it has a subscriber.next, which controls the output of the data in the stream.

Here are a few more questions:

  1. Can I start streams more than once, and if so, will the output interfere with each other as I start streams more than once?
  2. Now that we have a start stream, can we close the stream?

For the first question, answer first, you can start multiple times, and streams that start multiple times are independent of each other. This can be verified by the following example:

import { Observable } from "rxjs";
// Record the time
const now = new Date().getTime();

/ / create the stream
const stream$ = new Observable(subscriber= > {
  setTimeout(() = > {
    subscriber.next([1.2.3]);
  }, 500);
  setTimeout(() = > {
    subscriber.next({ a: 1000 });
  }, 1000);
  setTimeout(() = > {
    subscriber.next("end");
  }, 3000);
  setTimeout(() = > {
    subscriber.complete();
  }, 4000);
});

/ / start the flow
const subscription1 = stream$.subscribe({
  complete: () = > console.log("done"),
  next: v= > console.log(new Date().getTime() - now, "ms stream1", v),
  error: () = > console.log("error")});// Start the stream after 1s delay
setTimeout(() = > {
  const subscription2 = stream$.subscribe({
    next: v= > console.log(new Date().getTime() - now, "ms stream2", v)
  });
}, 1000);

// output
// 506ms stream1 [1, 2, 3]
// 1002ms stream1 {a: 1000}
// 1505ms stream2 [1, 2, 3]
// 2009ms stream2 {a: 1000}
// 3002ms stream1 end
// done
// 4006ms stream 2 end
Copy the code

In the example above, stream 1 is initially started and stream 2 is started after a delay of 1s. You can see from the output that the outputs of the two streams are actually independent of each other, and in fact they are designed to be independent of each other and do not interfere with each other.

For problem 2, you can guess from the above that the stream$.subscribe() return value subscription has a method unsubscribe that stops the stream. The demo code is as follows:

import { Observable } from "rxjs";

const now = new Date().getTime();

const stream$ = new Observable(subscriber= > {
  setTimeout(() = > {
    subscriber.next([1.2.3]);
  }, 500);
  setTimeout(() = > {
    subscriber.next({ a: 1000 });
  }, 1000);
  setTimeout(() = > {
    subscriber.next("end");
  }, 3000);
  setTimeout(() = > {
    subscriber.complete();
  }, 4000);
});

/ / start the flow
const subscription = stream$.subscribe({
  complete: () = > console.log("done"),
  next: v= > console.log(v),
  error: () = > console.log("error")});// After 1s, close the stream
setTimeout(() = > {
  subscription.unsubscribe();
}, 1000);
// output 
// [1,2,3] // 500ms
// {a: 1000} // at 1000ms
Copy the code

The code above terminates the stream at 1000ms by executing the subscription. Unsubscribe (). Subsequent output does not trigger the next function, but this does not mean that subsequent 3000ms and 4000ms callbacks will continue. Just because the stream is closed, next’s callback will not be performed.

That’s how a stream is created, started, and stopped. In this, there are several variables, rearrange the code, as follows:

import { Observable } from "rxjs";

// Create a stream
const stream$ = new Observable(subscriber= > {
  setTimeout(() = > {
    subscriber.next([1.2.3]);
  }, 500);
});

// How to consume data generated by streams, Observer
const observer = {
  complete: () = > console.log("done"),
  next: v= > console.log(v),
  error: () = > console.log("error")};/ / start the flow
const subscription = stream$.subscribe(observer);

setTimeout(() = > {
  / / stop the flow
  subscription.unsubscribe();
}, 1000);
Copy the code

There are three variables involved in this process

  1. stream$In Rxjs, it is an Observable, which is difficult to understand simply from the meaning of English translation to Chinese. But its essence is a collection of data generated over time, which is easier to understand as a stream. The object has a subscribe method, which starts the stream only after it is called. Note that each stream that is started multiple times is independent and does not interfere with each other.
  2. observer, is in the codestream$.subscribe(observer)Corresponding to Rxjs, it is also called observer, which is difficult to understand from the meaning of English translation to Chinese. In terms of behavior, it is nothing more than defining how to process the data generated by the above flow
  3. subscription, that is,const subscription = stream$.subscribe(observer);Rxjs is also called subscription, which is essentially a start up stream. As mentioned earlier, each start stream is independent of each other. This start stream is stored in the subscription. Unsubscribe is provided to stop the stream.

Observable, observer, and subscription: Observable, observer, and Subscription An Observable defines what data to generate, its subscribe method receives an observer, and starts generating data. The return value, subscription, stores the stream that has been opened. A colleague has the unscbscribe method, which can stop the flow. The formula is as follows:

Observable: a collection of data generated over time, understood as a stream, whose subscribe method initiates the stream observer: Decide how to handle data subscription: Store streams that have already been started and whose unsubscribe method can stop the stream

The operator

Operators for Rxjs can be said to be very important, but for beginners, you can not be immersed in understanding a operator, first understand the concept of the above is more important, so here is not to do a detailed introduction, in the actual combat encountered to the official website.

Subject

Subject is also an important concept in Rxjs. It is not easy to understand in English.

import { Subject } from "rxjs";

/ / create the subject
const subject = new Subject();

// Subscribe to an Observer
subject.subscribe(v= > console.log("stream 1", v));
// Subscribe to an Observer
subject.subscribe(v= > console.log("stream 2", v));
// Wait 1s to subscribe to an observer
setTimeout(() = > {
  subject.subscribe(v= > console.log("stream 3", v));
}, 1000);
// Generate data 1
subject.next(1);
// Generate data 2
subject.next(2);
// delay 3s to generate data 3
setTimeout(() = > {
  subject.next(3);
}, 3000);
// output
// stream 1 1 //
// stream 2 1 //
// stream 1 2 //
// stream 2 2 //
// stream 1 3 //3s output
// stream 2 3 //3s output
// stream 3 3 //3s output
Copy the code

As you can see, the Subject’s behavior is very close to the publish-and-subscribe pattern: Subscribe to subscribe, next triggers. Events are subscribed through subscribe and events are triggered using next, thus realizing a publish-subscribe pattern. It can be said that when the author saw this Subject, he finally got through with the existing knowledge system. After that, he re-read the official documents and understood a little. Of course, subject has other uses that are not detailed here

conclusion

Having said so much, in fact, the whole Rxjs content is very much, the original intention of this article is just to pit the record, to help the students who have not entered the entrance to grasp the essence of faster, read before reading the official website documents, compared to the first to understand a few English concepts, can take many detours. Stream start, stream stop and so on are the author’s personal understanding, not a unified term, just easy to understand, do not pay too much attention to.

I am also in the study, mutual encouragement.

Refer to the article

  1. Blog.crimx.com/2018/02/16/…
  2. Blog.jerry-hong.com/series/rxjs…