1.基本介绍
参考手册:https://www.npmjs.com/package/rxjs
**中文手册:**https://cn.rx.js.org/
RxJS 是 ReactiveX 编程理念的 JavaScript 版本。ReactiveX 来自微软,它是一种针对异步数据流的编程。简单来说,它将一切数据,包括 HTTP 请求,DOM 事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。
RxJS 是一种针对异步数据流编程工具,或者叫响应式扩展编程;可不管如何解释 RxJS 其目标就是异步编程,Angular 引入 RxJS 为了就是让异步可控、更简单。
RxJS 里面提供了很多模块。这里我们主要给大家讲 RxJS 里面最常用的 Observable 和 fromEvent。
注意:RxJS的Observable 和 Promise 很像,但是更加的强大!
2.异步编程方案
目前常见的异步编程的几种方法:
1、回调函数
组件里面使用服务的方法:
//2、callback获取异步数据
this.request.getCallbackData((data: any) => {
console.log(data);
});
服务里面定义的方法:
getCallbackData(cb: any) { //传进来一个回调函数,我们异步进行调用,从而实现信息的延迟回传
setTimeout(() => {
var username = '张三';
// return username;
cb(username);
}, 1000);
}
2、事件监听/发布订阅
EventEmitter
3、Promise
//3、promise获取异步数据
var promiseData = this.request.getPromiseData();
promiseData.then((data) => {
console.log(data);
})
getPromiseData() {
return new Promise((resolve) => {
setTimeout(() => {
var username = '张三--Promise';
resolve(username);
}, 3000);
});
}
注意:async/await 本质上是Promise!
4、Rxjs
3.Rxjs的使用(Observable)
注意:angular里面默认集成了rxjs,不需要安装,直接使用即可!
(1)基本使用
组件里面使用服务的方法:
import { RequestService } from '../../services/request.service';
constructor(public request: RequestService) { }
//4、rxjs获取异步方法里面的数据
var rxjsData=this.request.getRxjsData(); //Observable对象
rxjsData.subscribe((data)=>{ //使用subscribe接收数据,相当于.then
console.log(data);
})
服务里面定义的方法:
import { Observable } from 'rxjs';
getRxjsData() {
return new Observable<any>((observer) => {
setTimeout(() => {
var username = '张三--Rxjs';
observer.next(username); //成功情况的返回,使用next函数,相当于resolve
// observer.error('数据') //失败情况的返回,使用error函数,相当于reject
}, 3000);
});
}
从上面列子可以看到 RxJS 和 Promise 的基本用法非常类似,除了一些关键词不同。Promise
里面用的是 resolve() 和 then(),而 RxJS 里面用的是 next() 和 subscribe()。
从上面例子我们感觉Promise 和 RxJS 的用法基本相似。其实Rxjs相比Promise 要强大很多。
比如 Rxjs 中可以中途撤回、Rxjs 可以发射多个值、Rxjs 提供了多种工具函数等等。
(2)unsubscribe 取消订阅(不同于ajax取消请求)
Promise 的创建之后,动作是无法撤回的。Observable 不一样,动作可以通过 unsbscribe() 方法中途撤回,而且 Observable 在内部做了智能的处理。
通过unsubscribe可以中途撤回订阅(在实际场景中,请求还是会发出去,只不过接收到的结果我们不往下进行了)
getRxjsData() {
return new Observable<any>((observer) => {
setTimeout(() => {
var username = '张三--Rxjs';
observer.next(username); //这里被拦截了
// observer.error('数据')
}, 3000);
});
}
//5、过一秒以后撤回刚才的操作
var streem = this.request.getRxjsData();
var d = streem.subscribe((data) => {
console.log(data); //这里就什么都没有了
})
setTimeout(() => {
d.unsubscribe(); /*1s之后取消订阅*/
}, 1000)
注意:取消订阅是拦截了next函数,不会触发,从根源进行取消!
(3)实现执行多次的异步任务
首先明确:Promise是不具备这个能力的
getPromiseIntervalData() {
return new Promise((resolve) => {
setInterval(() => {
//这里面可以是ajax请求等内容
var username = '张三--Promise Interval';
resolve(username); //第一次执行完毕就直接resolve,状态改变之后就不能再触发了
}, 1000);
});
}
//6、promise 执行多次(没有这个能力)
var intervalData = this.request.getPromiseIntervalData();
intervalData.then((data) => {
console.log(data); //只会输出一次
})
那么Rxjs如何做?
getRxjsIntervalData() {
let count = 0;
return new Observable<any>((observer) => {
setInterval(() => {
count++;
//这里面可以是ajax请求等内容
var username = '张三--Rxjs-Interval' + count;
observer.next(username);
// observer.error('数据')
}, 1000);
});
}
//7、rxjs执行多次
var streemInterval = this.request.getRxjsIntervalData();
streemInterval.subscribe((data) => {
console.log(data); //不断输出username
})
应用场景:比如爬虫,不断爬取
或者一些需要轮询的场景、不断重复动作的场景等
(4)用管道方法对返回的数据进行拦截处理
**注意:**Angular6 以后使用以前的 rxjs 方法,必须安装 rxjs-compat 模块。
npm install rxjs-compat
import { Observable } from 'rxjs';
import 'rxjs/Rx';
如果你不需要对旧版本的 RxJS 操作符保持兼容性,即你的应用程序不使用旧版的 RxJS 操作符,那么就不需要安装 rxjs-compat
模块。
在 Angular 6+ 中,推荐直接导入操作符并按照新的方式使用它们,而不依赖于 rxjs-compat
模块。
import { map, filter } from 'rxjs/operators';
使用filter函数进行数据过滤
注意:要套在pipe管道里面,使用相关的函数
getRxjsIntervalNum() {
let count = 0;
return new Observable<any>((observer) => {
setInterval(() => {
count++;
observer.next(count);
// observer.error('数据')
}, 1000);
});
}
//8、用工具方法对返回的数据进行处理
var streemNum = this.request.getRxjsIntervalNum();
streemNum.pipe(
filter((value) => {
if (value % 2 == 0) {
return true;
}
return false;
})
).subscribe((data) => {
console.log(data);
});
使用map函数进行数据处理
var streemNum = this.request.getRxjsIntervalNum();
streemNum.pipe(
map((value) => {
return value * value;
})
).subscribe((data) => {
console.log(data);
});
使用 map + filter 进行处理
var streemNum = this.request.getRxjsIntervalNum();
streemNum.pipe(
filter((value) => {
return value % 2 == 0; //过滤出来偶数
}),
map((value) => {
return value * value; //对每一个数据进行平方
})
).subscribe((data) => {
console.log(data);
});
4.实例:rxjs构造路由守卫服务的返回值
路由配置项的canActivate项介绍:
canActivate: [RoleGuardScreen]
canActivate
是 Angular 路由模块中的一个路由守卫(Route Guard)。路由守卫用于保护路由,并控制用户是否被允许进入或离开特定的路由。
在上述代码中,canActivate: [RoleGuardScreen]
表示将 RoleGuardScreen
标识为要应用于该路由的路由守卫。
RoleGuardScreen
是一个自定义的路由守卫服务或守卫类的名称。它实现了 CanActivate
接口,该接口定义了一个方法 canActivate()
,在导航到某个路由时将被调用。这个方法接受两个参数:route
和 state
,分别表示要导航的目标路由和当前路由状态。
路由守卫在 canActivate()
方法中执行一些逻辑来判断用户是否被允许访问该路由。它可以进行各种验证操作,例如检查用户是否具有特定的角色、权限、认证状态等。如果验证失败,路由守卫可以返回一个 false
值,将用户重定向到其他页面或阻止用户进入该路由。
当路由守卫的 canActivate()
方法返回 true
时,导航继续,用户被允许访问该路由。当返回 false
时,导航被中止,用户被重定向到另一个路由或保持在当前页面。
通过在路由配置中指定 canActivate: [RoleGuardScreen]
,可以将 RoleGuardScreen
应用于该特定路由,以确保在导航到该路由之前执行相应的验证逻辑并保护该路由。
路由守卫canActivate方法的返回值:
路由守卫的 canActivate()
方法可以返回以下类型之一:
Observable<boolean>
:当路由守卫需要异步处理时,可以返回一个 Observable 对象,并在 Observable 中使用next()
发射一个布尔值来指示是否允许导航。Observable 可以发出多个值,但当它发出false
时,导航将被取消。当 Observable 完成时,导航将继续。Promise<boolean>
:可以返回一个 Promise 对象,它可以异步确定是否允许导航。当 Promise 的解析值为false
时,导航将被取消。解析值为true
或 Promise 完成时,导航将继续。boolean
:可以直接返回一个布尔值。true
表示允许导航,false
表示取消导航。
需要注意的是,如果返回值是一个 Observable 对象或 Promise 对象,Angular 路由模块会等待该 Observable 或 Promise 完成,然后根据返回值来决定是否允许导航。
服务的构造:
import { Route } from '@angular/compiler/src/core';
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { HttpService } from '@services';
import { Observable } from 'rxjs';
import { NzMessageService } from 'ng-zorro-antd/message';
@Injectable({ providedIn: 'root' })
export class RoleGuardScreen implements CanActivate {
constructor(
private route: Router,
private httpService: HttpService,
private router: Router,
public message: NzMessageService,
) {}
// eslint-disable-next-line @typescript-eslint/member-ordering
public roleId: any;
getRoleId() {
const cookieTpl = document.cookie.split('; ');
cookieTpl.forEach((item) => {
if (item.indexOf('role-code') !== -1) {
const newArr = item.split('=');
this.roleId = newArr[1]; //得到cookie里面的角色id
console.log('this.roleId', this.roleId);
}
});
}
canActivate( //路由守卫,默认canActivate: [RoleGuardScreen],会调用这个方法
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
this.getRoleId();
return this.checkRole(this.roleId);
}
// 低权限
checkRole(roleId): Observable<any> | UrlTree | boolean {
console.log('roleId', roleId);
if (roleId === '2') {
location.hash = '/cloud-soc/report/audit/soc-log'; //如果id为2就跳转到特定的路径:将浏览器的 URL 锚点(hash)设置为 '/cloud-soc/report/audit/soc-log' 。这实际上是一种改变浏览器地址栏中的 URL,并触发浏览器进行相应的页面跳转。
// return this.router.parseUrl('/cloud-soc/report/');
} else {
return new Observable((observer) => {
observer.next(true);
observer.complete();
});
}
}
}
canActivate
是一个路由守卫方法,它决定是否允许用户导航到特定路由。在 canActivate
方法中,你调用了 getRoleId()
方法来获取用户的角色信息,并将角色 ID 传递给 checkRole()
方法来检查用户的权限。
现在让我们讨论为什么使用 RxJS Observable 作为返回类型。在 Angular 中,canActivate
方法可以返回一个布尔值、一个 UrlTree
对象、一个 Observable
或一个 Promise
。这样设计是为了允许开发者在权限检查过程中执行异步操作,比如从服务器获取权限信息。 ——> 这是angular路由的默认规定!
在这里,canActivate
方法返回了一个 Observable 对象:
return new Observable((observer) => {
observer.next(true);
observer.complete();
});
Observable 发出一个值为 true
的 next 通知,然后立即完成(complete)。这样做的效果是立即允许导航。
使用:
{
path: 'overview',
data: { breadcrumb: '运营报告' },
component: ReportOverviewComponent,
canActivate: [RoleGuardScreen],
},
{
path: 'audit',
data: { breadcrumb: '审计日志' },
component: ReportLayoutComponent,
children: [
{
path: 'soc-log',
data: { breadcrumb: 'SOC审计日志' },
component: SocAuditLogComponent,
},
{
path: 'sse-log',
data: { breadcrumb: 'SSE审计日志' },
component: DeviceAuditLogComponent,
},
// {
// path: 'user-log',
// data: { breadcrumb: '用户审计日志' },
// component: UserAuditLogComponent,
// },
{
path: '',
redirectTo: 'soc-log',
},
],
canActivate: [RoleGuard],
},
5.Observable和Subject
Subject是什么,有什么特点?
在RxJS(Reactive Extensions for JavaScript)中,Subject
是一种特殊类型的 Observable,同时也是一个观察者(Observer)。它允许多个观察者订阅它,并且可以通过调用 next
, error
, 和 complete
方法来从外部向它推送新的值,错误信息或者完成信号。——> 它相当于是一个Observable与Observer之间的中间商!
主要特点包括:
多播性(Multicasting):
Subject
是一种多播的 Observable,意味着它可以同时向多个观察者传播数据。当你调用
next
方法时,所有订阅该Subject
的观察者都会接收到新的数据。状态维护:
Subject
会维护当前值,并在使用next方法时将最新值立即发送给它们,这对于在任何时候加入应用程序的新观察者是有用的。可以作为观察者:
Subject
既是 Observable 又是 Observer。它可以订阅其他 Observables,并可以被其他 Observers 订阅(作为中间商)。不是纯粹的函数式编程模型: 与纯粹的函数式编程模型不同,
Subject
允许在程序中引入可变状态,因为它允许通过调用next
方法来推送新值。
**使用 Subject
可以实现多个部分共享同一份数据流,从而使得多个部分能够响应同一个数据源的变化。**然而,要注意在使用时适当地处理状态和副作用,以确保程序的可维护性和一致性。
import { Subject } from 'rxjs';
const subject = new Subject<number>(); //不需要传递回调函数,和Observable窗口的时候不同
// 订阅 Subject
const subscription = subject.subscribe((value) => {
console.log('Received value:', value);
});
// 推送新值给所有订阅者(不用在回调函数里面推送)
subject.next(1);
subject.next(2);
// 取消订阅
subscription.unsubscribe();
Observable与Observer对比?分别是什么?
我们在写Observable时一般都是这么写:其实它的回调函数的参数就是Observer
new Observable<any>((observer) => {
setTimeout(() => {
var username = '张三--Rxjs';
observer.next(username); //成功情况的返回,使用next函数,相当于resolve
// observer.error('数据') //失败情况的返回,使用error函数,相当于reject
}, 3000);
});
Observable: Observable 是一个表示数据流的对象,它可以被观察,可以被订阅以接收它发出的值。Observable 可以发出零个、一个或多个值,也可以在完成时发出完成信号或在出现错误时发出错误信息。
Observer: Observer 是用于监听 Observable 发出的值、完成信号或错误信息的对象。它通常由三个回调函数组成:
next
: 处理 Observable 发出的新值。error
: 处理 Observable 发出的错误。complete
: 处理 Observable 发出的完成信号。注意:以上方法是没有返回值的!
let subscription = rxjsData.subscribe((data)=>{ //使用subscribe接收数据,相当于.then
console.log(data);
})
subscribe: subscribe
是 Observable 上的方法,用于订阅 Observable。当你订阅一个 Observable 时,你会得到一个 Subscription 对象,该对象可以用于取消订阅。
Observable和Subject的对比?
Observable
和 Subject
是 RxJS 中两个重要的概念,它们用于处理异步数据流和实现响应式编程。以下是它们的对比:
一、Observable(可观察对象):
- 单播(Unicast):
Observable
是单播的,每个订阅者(Observer)都会创建一个新的执行路径。
- 不可变:
Observable
本身是不可变的,它不会发出任何数据,只有通过调用next
,error
, 和complete
方法才能向观察者发出数据、错误或者完成信号。
- 推送数据:
- 通过
next
方法向订阅的观察者推送新的数据。
- 通过
- 订阅和取消订阅:
- 使用
subscribe
方法订阅 Observable,返回一个 Subscription 对象,可以用于取消订阅以停止接收数据。
- 使用
- 冷 Observable:
Observable
在被订阅时才开始执行,每个订阅者都有独立的执行路径。
二、Subject(主题):
- 多播(Multicast):
Subject
是多播的,它可以同时将数据推送给多个订阅者。
- 可变:
Subject
是可变的,可以通过调用next
,error
, 和complete
方法向观察者发出数据、错误或者完成信号。
- 推送数据:
- 通过
next
方法向所有订阅的观察者推送新的数据。
- 通过
- 订阅和取消订阅:
- 使用
subscribe
方法订阅 Subject,返回一个 Subscription 对象,可以用于取消订阅以停止接收数据。
- 使用
- 热 Observable:
Subject
是热 Observable,它可以在任何时候发出数据,不受订阅时间的影响。
三、选择使用时的考虑因素:
- 如果你需要创建一个可观察对象,并且希望每个订阅者都有独立的执行路径,使用
Observable
。 - 如果你想要创建一个可以多播给多个订阅者的数据源,并且希望新的观察者可以接收到最新的值,使用
Subject
或者BehaviorSubject
。 - 如果你需要一个特殊类型的
Subject
,它可以记录最新的值并在新的订阅者订阅时立即推送该值,使用BehaviorSubject
。 - 如果你需要一个特殊类型的
Subject
,它可以记录推送的所有值的日志,使用ReplaySubject
。 - 如果你需要一个特殊类型的
Subject
,它可以只向后续订阅者推送最新值,使用AsyncSubject
。
注意:可以说Observable类似于Promise,而Subject类似于Pubsub.js!!!——> 很巧妙的比喻
1.Observable 类比于 Promise:
- Observable 和 Promise 都用于处理异步操作,提供了一种处理异步操作结果的方式。
- Promise 主要用于一次性的异步操作,可以获取成功的结果或失败的原因,而 Observable 更适用于表示持续的异步数据流。
- Observable 具有丰富的操作符,可以对数据流进行转换、过滤、组合等处理,而 Promise 只能通过
.then()
和.catch()
处理结果。
2.Subject 类比于 PubSub.js 插件:
- Subject 和 PubSub.js 插件类似,都支持多个订阅者(观察者)。
- Subject 是 RxJS 中的一种特殊类型,可以作为 Observable 也可以作为 Observer,同时也具有多播的能力,类似于 PubSub 的多播特性。
- PubSub.js 插件实现了简单的发布-订阅模式,它允许你发布事件,然后订阅这些事件的通知,和 Subject 在某种程度上有相似之处。
在这种比较下,可以说 Subject 在一些方面类似于 PubSub.js 插件,但是 Subject 是 RxJS 中的一种工具,具有更丰富的特性和功能,适用于处理更复杂的异步数据流。而 PubSub.js 插件是一个简单的发布-订阅模式的实现,适用于简单的事件通知场景。
6.RxJS中的四种Subject
简介: RxJS中有四种不同类型的Subject,它们分别是Subject、BehaviorSubject、ReplaySubject和AsyncSubject。本文将介绍这四种Subject的用法、区别以及适用的应用场景,并提供代码示例。
RxJS(Reactive Extensions for JavaScript)是一个功能强大的响应式编程库,它提供了许多强大的工具和概念来处理异步数据流。
在RxJS中,Subject是一个重要的概念,它充当了一个可观察对象和观察者之间的桥梁(具体详见深入浅出 RxJS 核心原理(响应式编程篇))。
RxJS中有四种不同类型的Subject,它们分别是Subject、BehaviorSubject、ReplaySubject和AsyncSubject。本文将介绍这四种Subject的用法、区别以及适用的应用场景,并提供代码示例。
一、Subject
Subject是最简单的一种Subject类型。它既是可观察对象(Observable),也是观察者(Observer)。Subject会维护一个观察者列表,并将它们通知给任何订阅它的观察者。
常见用法示例:
- 基本使用
import { Subject } from 'rxjs';
const subject = new Subject<number>();
// 订阅 Subject
const subscription = subject.subscribe((value) => {
console.log('Received value:', value);
});
// 推送新值给所有订阅者
subject.next(1);
subject.next(2);
// 取消订阅
subscription.unsubscribe();
- 多播(Multicasting)
Subject
可以实现多播,即多个观察者同时收到相同的数据。
import { Subject } from 'rxjs';
const subject = new Subject<number>();
// 多个观察者订阅同一个 Subject
subject.subscribe((value) => {
console.log('Observer 1 received:', value);
});
subject.subscribe((value) => {
console.log('Observer 2 received:', value);
});
// 推送新值给所有订阅者
subject.next(1);
subject.next(2);
- 将 Subject 作为 Observable,使用.asObservable()函数
你可以将 Subject
当作一个普通的 Observable
来使用。
import { Subject } from 'rxjs';
const subject = new Subject<number>();
subject.subscribe((value) => {
console.log('Observer 1 received:', value);
});
subject.next(1);
// 也可以将 Subject 当作 Observable 使用
subject.asObservable().subscribe((value) => {
console.log('Observer 2 received:', value);
});
subject.next(2);
- 错误处理(和Observable一样的)
Subject
也可以处理错误信息。
import { Subject } from 'rxjs';
const subject = new Subject<number>();
subject.subscribe(
(value) => console.log('Received value:', value),
(error) => console.error('Error:', error)
);
subject.next(1);
subject.error('Something went wrong!');
这些示例展示了 Subject
的一些常用用法,包括基本的订阅、多播、将 Subject
作为 Observable
使用以及错误处理。Subject
的灵活性使其成为 RxJS 中强大的工具,可以用于多种场景,特别是在多个观察者需要同时观察同一数据流的情况下。
应用场景:
- 在需要将一个值或事件广播给多个观察者的场景中使用Subject。
- 当需要将已存在的非RxJS代码转化为响应式时,Subject是一个不错的选择。
二、BehaviorSubject
BehaviorSubject是一种特殊类型的Subject,它会记住最新的值,并在有新的观察者订阅时立即将这个最新值发送给它们(subject在订阅时不会推送值,而是在下一次进行next的时候才推送)。
用法示例:
const behaviorSubject = new BehaviorSubject('Initial value'); //可以传递一个初始值,作为当前默认的最新值
behaviorSubject.subscribe((data) => { //订阅之后立即收到初始值
console.log('Observer 1:', data);
});
behaviorSubject.next('Hello');
behaviorSubject.subscribe((data) => { //订阅之后立即收到当前的最新值(即上一次next的值)
console.log('Observer 2:', data);
});
输出结果:
Observer 1: Initial value
Observer 1: Hello
Observer 2: Hello
应用场景:
- 当需要将当前状态或初始值发送给新的观察者时,可以使用BehaviorSubject。
- 在状态管理中,BehaviorSubject可以用作存储和访问状态的中心数据源。
三、ReplaySubject
ReplaySubject会在有新的观察者订阅时,向它们发送之前发送过的数据,可以指定发送的历史数据数量。
用法示例:
const replaySubject = new ReplaySubject(2);
replaySubject.subscribe((data) => {
console.log('Observer 1:', data);
});
replaySubject.next('Value 1');
replaySubject.next('Value 2');
replaySubject.next('Value 3');
replaySubject.subscribe((data) => {
console.log('Observer 2:', data);
});
输出结果:
mathematicaCopy code
Observer 1: Value 1
Observer 1: Value 2
Observer 1: Value 3
Observer 2: Value 2
Observer 2: Value 3
应用场景:
- 当需要将过去的数据重新发送给新的观察者时,可以使用ReplaySubject。
- 在需要缓存历史数据的场景中,ReplaySubject非常有用。
四、AsyncSubject
AsyncSubject只会在Subject完成时发送最后一个值给观察者。如果Subject还没有完成,那么AsyncSubject不会发送任何值。
用法示例:
const asyncSubject = new AsyncSubject();
asyncSubject.subscribe((data) => {
console.log('Observer 1:', data);
});
asyncSubject.next('Value 1');
asyncSubject.next('Value 2');
asyncSubject.next('Value 3');
asyncSubject.subscribe((data) => {
console.log('Observer 2:', data);
});
asyncSubject.complete();
输出结果:
Observer 1: Value 3
Observer 2: Value 3
应用场景:
- 当只关心Subject完成后的最终结果时,可以使用AsyncSubject。
- 在需要等待异步操作完成后获取结果的场景中,AsyncSubject非常适用。
总结
在开发中我们常用的是Subject,但是一些场景中我们还是需要根据具体情况来使用。
Subject类型 | 用法 | 区别 | 适用场景 |
---|---|---|---|
Subject | 将值或事件广播给多个观察者 | 无法回放历史数据 | - 广播值或事件给多个观察者 - 将非RxJS代码转换为响应式 |
BehaviorSubject | 将最新值发送给新的观察者 | 记住最新值 | - 初始值或当前状态的广播 - 状态管理的中心数据源 |
ReplaySubject | 向新的观察者发送历史数据 | 可以回放历史数据 | - 重新发送过去数据给新的观察者 - 缓存历史数据的场景 |
AsyncSubject | 在完成时发送最后一个值 | 只发送最后一个值 | - 只关心Subject完成后的最终结果 - 等待异步操作完成后获取结果 |
希望本文能帮助您更好地理解RxJS中四种Subject的用法和区别,并在实际开发中正确地应用它们。