Introduction to basic concepts of RxJS

Angular development has to mention another great artifact, RxJS. It is a very powerful tool that can help you better handle asynchronous programming in JavaScript. The following are some basic knowledge and resources about RxJS for your reference.

What is RxJS?

RxJS stands for Reactive Extended JavaScript. It is a library for processing event streams and asynchronous data streams, which can be combined to produce more complex results.

RxJS core concepts

  • Observable: Represents a callable collection of future values ​​or events.
  • Observer: A collection of callback functions used to process the values ​​emitted by the Observable, including next, error and complete.
  • Subscription: Represents the execution of Observable and is mainly used to cancel the execution of Observable.
  • Operators: Pure functions that allow pure transformation of values ​​in Observable in a declarative manner, such as map(), filter(), concat(), etc.
  • Subject: Equivalent to EventEmitter, and is the only way to multicast values ​​to multiple observers.

Observable

In RxJS, an Observable represents a collection that can push 0 or more values, which is equivalent to a stream. There are several ways to create and convert Observables. Once an Observable is created, you can use a variety of additional operators to easily create, combine, and modify Observables.

Here are some core concepts about Observable:

Create Observable

You can use operators such as of, from, interval, timer, ajax, createetc. to create an Observable, depending on the type of data source you need to use. For example:

// 从一个静态值创建一个Observable
const myObservable = of('hello', 'world');

// 从数组中创建一个Observable
const myArrayObservable = from([1, 2, 3, 4, 5]);

// 创建一个每秒发送递增整数的Observable
const intervalObservable = interval(1000);

// 延迟三秒后发射单个值的Observable
const timerObservable = timer(3000, 1000);

Subscribe to Observable

Observables are lazy, they only start pushing values ​​when you subscribe to them. You can use .subscribe()methods to subscribe to an Observable and then process the emitted values.

myObservable.subscribe(value => console.log(value));

Unsubscribe

Once you subscribe to an Observable, you need to decide when to unsubscribe. Using .subscribe()the returned subscription object, .unsubscribe()the subscription can be unsubscribed by calling .

const subscription = myArrayObservable.subscribe(value => console.log(value));

// 在3秒后取消订阅
setTimeout(() => {
    
    
  subscription.unsubscribe();
}, 3000);

handling errors

When an Observable emits error messages, you need to handle these errors accordingly. You can use catchErrorthe operator to catch and handle errors.

myObservable.pipe(
    catchError(error => of(`An error occurred: ${
      
      error}`))
  ).subscribe(value => console.log(value));

Connect multiple Observables

You can use connectable operators to subscribe to multiple Observables simultaneously and connect them together. Similar operators include merge, concat, combineLatest, forkJoinetc.

const observable1 = of('hello');
const observable2 = of('world');

const combinedObservable = combineLatest([observable1, observable2]);

combinedObservable.subscribe(value => console.log(value)); // ["hello", "world"]

Observer

In RxJS, an Observer represents an observer object that can handle zero or more values ​​emitted by an Observable and can react to errors and completion events generated by the Observable.

The following are some core concepts about Observer:

Create Observer

You can create an Observer using three properties next: , errorand .complete

const myObserver = {
    
    
  next: value => console.log(value),
  error: err => console.error(err),
  complete: () => console.log('Observable completed')
};

Subscribe to Observable

In order to subscribe to an Observable, you need to pass the Observer as a parameter to the method on the Observable .subscribe().

myObservable.subscribe(myObserver);

When an Observable emits a new value, it calls the Observer's nextproperty to push the value. Likewise, when an Observable emits an error message, it calls the Observer's errorproperty and calls completethe property to mark the Observable as completed.

const myObservable = of('hello', 'world');

// 订阅Observable
myObservable.subscribe({
    
    
  next: value => console.log(value),
  error: err => console.error(err),
  complete: () => console.log('Observable completed')
});

handling errors

You may choose to define only Observers for nextand errorto handle error messages emitted by the Observable.

const myObserver = {
    
    
  next: value => console.log(value),
  error: err => console.error(err)
};

myObservable.subscribe(myObserver);

Handle completion event

You may choose to define only Observers for nextand completeto handle events when the Observable completes.

const myObserver = {
    
    
  next: value => console.log(value),
  complete: () => console.log('Observable completed')
};

myObservable.subscribe(myObserver);

Subscription

Subscription is another important concept in RxJS. When we use Observable to subscribe to a data source, it returns a Subscription object, which is used to disconnect from the data source.

subscription

In order to subscribe to an Observable, we must call the Observable's subscribe() function. This function will return a Subscription object.

const subscription = myObservable.subscribe(value => {
    
    
    console.log('Received value:', value);
});

unsubscribe

If we want to cancel a subscription, we can call the unsubscribe() method on the Subscription object.

subscription.unsubscribe();

After calling unsubscribe(), we will no longer receive any response from the Observable.

Resource cleanup after subscription

In addition, Subscription also provides the add() and remove() methods, both of which accept a sub-subscription (sub-Subscription).

They can be used to register and unregister subscriptions on the parent Subscription. When the parent Subscription is canceled, all registered child Subscriptions will automatically unsubscribe.

const parentSubscription = new Subscription();
const childSubscription = myObservable.subscribe(value => {
    
    
    console.log('Received value:', value);
});

parentSubscription.add(childSubscription); // 注册子订阅

// 父 Subscription 将取消所有的子 Subscription。
parentSubscription.unsubscribe(); 

Operator

In RxJS, an Operator is a function that receives an Observable's input data and outputs a transformed Observable.

One or more Operators can be formed into a pipeline (pipe), through which the data is gradually passed and gradually converted into the form we need.

pipeline

A pipeline is a chain of calls composed of a series of Operators. In order to create a pipe, we need to use the pipe() method on the Observable and pass the Operator as a parameter.

import {
    
     map, filter } from 'rxjs/operators';

const myObservable = of(1, 2, 3, 4, 5);

myObservable.pipe(
    filter(value => value % 2 === 0), // 过滤偶数
    map(value => value * 10) // 将值乘以 10
).subscribe(result => {
    
    
    console.log('Received result:', result);
});

pure function

In RxJS, Operators should be pure functions - i.e. always produce the same output given a specific input. This makes them very easy to test, reuse and compose.

Common Operators

RxJS comes with many built-in Operators, such as map, filter, reduce, zip, merge, concat, etc. In addition, there are many community-developed Operator libraries, such as ngRx, ngrx-data, ngx-query and other libraries. These libraries provide a large number of Operators that can be used to simplify application development in different scenarios.

Subject

In RxJS, Subject is a special kind of Observable. The difference with normal Observables is that Subjects can emit values ​​multiple times like events, and they send values ​​simultaneously to all observers listening to the Subject.

There are two main variations of Subject:

BehaviorSubject

BehaviorSubject requires an initial value and will send the latest value to the observer whenever it is subscribed.

import {
    
     BehaviorSubject } from 'rxjs';

const subject = new BehaviorSubject('Initial value');

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverA: ${
      
      v}`)
});

subject.next('New value');

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverB: ${
      
      v}`)
});

// output:
// ObserverA: Initial value
// ObserverA: New value
// ObserverB: New value

In the above example, we create a BehaviorSubject and pass it a value initially. When I send a new value to the BehaviorSubject, it sends this value to all the observers subscribed to it. Note that even new values ​​sent after the second subscription will be sent to the new observer ObserverB.

ReplaySubject

ReplaySubject does not require initial values ​​when created, but can cache the most recently emitted n values, and new subscribers will receive playback of these values ​​immediately.

import {
    
     ReplaySubject } from 'rxjs';

const subject = new ReplaySubject(2); // 缓存最近2个值

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverA: ${
      
      v}`)
});

subject.next('Value 1');
subject.next('Value 2');
subject.next('Value 3');

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverB: ${
      
      v}`)
});

// output:
// ObserverA: Value 1
// ObserverA: Value 2
// ObserverA: Value 3
// ObserverB: Value 2
// ObserverB: Value 3

In the above example, we created a ReplaySubject and passed parameter 2 in the constructor. This means that the principal will cache the most recent 2 values.

When I send 3 values ​​to the playback topic, all observers subscribed to it receive these values.

Note that the new observer, ObserverB, receives the cached value immediately. In this example, 2 values ​​are cached and 3 values ​​have been emitted by the ReplaySubject, but the new observer will still be able to see the last two values ​​(Value 2 and Value 3).

AsyncSubject

AsyncSubject only emits the last value upon completion (that is, when the Subject's complete() method is called).

import {
    
     AsyncSubject } from 'rxjs';

const subject = new AsyncSubject();

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverA: ${
      
      v}`)
});

subject.next('Value 1');
subject.next('Value 2');

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverB: ${
      
      v}`)
});

subject.next('Value 3');
subject.complete();

// output:
// ObserverA: Value 3
// ObserverB: Value 3

In the above example, we created an AsyncSubject and subscribed to two observers. Then send three values ​​and call the complete() method. After this, AsyncSubject caches the last value and completion notification internally and sends this value to all subscribed observers ObserverA and ObserverB.

Since AsyncSubject emits a value only when the complete() method is called, if the complete() method is called without emitting a value, there will be no emissions.

Subject is a very useful Observable variant that can handle various cases of synchronous and asynchronous code, as well as some use cases of more complex RxJS operators.

BehaviorSubject

BehaviorSubject is similar to the Subject above, but it emits the last value when subscribed and resends this value on each update.

import {
    
     BehaviorSubject } from 'rxjs';

const subject = new BehaviorSubject('initial value');

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverA: ${
      
      v}`)
});

subject.next('Value 1');
subject.next('Value 2');

subject.subscribe({
    
    
  next: (v) => console.log(`ObserverB: ${
      
      v}`)
});

subject.next('Value 3');

// output:
// ObserverA: initial value
// ObserverA: Value 1
// ObserverA: Value 2
// ObserverB: Value 2
// ObserverA: Value 3
// ObserverB: Value 3

In the above example, we created a BehaviorSubject and passed the initial value. We subscribe to two observers (ObserverA and ObserverB) and send three values. Note that when the second observer subscribes, it immediately receives the latest value, Value 2, and is updated each time a new value is sent.

There is an important note about BehaviorSubject: BehaviorSubject requires an initial value to be provided at creation time, since it may need to emit it when no other value is available.

BehaviorSubject is typically used to represent "state" or "data source", and multiple components can share the same BehaviorSubject instance to get and update that data. It can also be used to cache the latest values.

RxJS practical tutorial

Here are some good RxJS practical tutorials for your reference:

Hopefully these resources will help you get started with RxJS quickly and make it easier to work with asynchronous streams in JavaScript programming.

Guess you like

Origin blog.csdn.net/lin5165352/article/details/132619475