状态管理从0到1:第1章

170 阅读4分钟

本章知识点:

  1. 什么是 Observable
  2. 什么是 Subject
  3. 什么是 BehaviorSubject
  4. 什么是 from

Observable

ObservableRxJS核心概念,可是说掌握了Observable就掌握了RxJS的核心技术,其它所有的东西都是围绕Observable服务的。

接下来我就用小学二年级的大白话,介绍一下Observable。 Observable是一个出版社,他只能生产书籍杂志,接收消费者的订阅,然后生产发货。 现在我们来建立这个出版社(我们把所有可以被订阅的单位后面都加上一个$符号,代表它可以被订阅):

const playboy$ = new Observable();

出版社建立好之后,我们就需要制定一个生产流,先假定一个订阅者Subscriber。 出版社可以有三个行为:

  1. next 向订阅者发送一件商品。
  2. error 报错,生产或发送商品时出错了
  3. complete 生产流结束,完成这次交易
const playboy$ = new Observable((subscriber) => {
	// 发送 武侠第一期
	subscriber.next("武侠第一期");
	// 发送 武侠第二期
	subscriber.next("武侠第二期");
});

此时生产流制定出来了,但实际上什么也不会发生,因为并没有人订阅我们的书。要生产流启动,需要有消费者来订阅。订阅的方式就是subscribe

// 小明订阅了武侠杂志
playboy$.subscribe({
	next(x) {
		console.log("小明收到" + x);
	}
});

控制台会输出:

小明收到武侠第一期
小明收到武侠第二期

注意:A.subcribe(B),是 B 订阅了 A。这点一定要理解记住。

如果你提前完成这个生产流,那后面的东西就都不会发送了。

const playboy$ = new Observable((subscriber) => {
	// 发送 武侠第一期
	subscriber.next("武侠第一期");
	// 可以喝了,确认收货
	subscriber.complete();
	// 武侠第二期,不会发送,因为已经结束
	subscriber.next("武侠第二期");
});
// 小明订阅了武侠杂志
playboy$.subscribe({
	next(x) {
		console.log("小明收到" + x);
	},
	complete() {
		console.log("停产");
	}
});

// logs:
// 小明收到武侠第一期
// 停产

如果你报出错误,后面的东西也都不会发送了。

const playboy$ = new Observable((subscriber) => {
	// 发送 武侠第一期
	subscriber.next("武侠第一期");
	// 报错,后面杂志都不会发送
	subscriber.error('有内鬼终止交易');
	// 武侠第二期,不会发送,因为已经结束
	subscriber.next("武侠第二期");
});
// 小明订阅了武侠杂志
playboy$.subscribe({
	next(x) {
		console.log("小明收到" + x);
	},
	error(err) {
		console.error("警告:" + err);
	},
});

// logs:
// 小明收到武侠第一期
// 警告:有内鬼终止交易

好了,以上就是RxJS最核心的内容了。围绕这个出版社,可以玩出花来,这出版社里可以同步生产,还可以异步生产,可以合并生产线,还可以控制生产节奏。丰富的操作符Operators后面会慢慢一起学习。

Subject

Subject是一个中间商,他既可以向出版社订阅书籍进货,也可以接收消费者的订阅发货(而observable,出版社只能发货,不能进货)。

现在我们来建立一个中间商(中间商也是可以被订阅的,所以加上$后缀):

const  businessman$ = new Subject();

和出版社一样,也需要有人订阅:

// 小明订阅了
businessman$.subscribe({
	next: (v) => console.log("小明收到" + v)
});
// 小刚订阅了
businessman$.subscribe({
	next: (v) => console.log("小红收到" + v)
});

此时控制台不会有任何反应,尽管已经有消费者订阅了,但中间商并没有发货。 我们发送两本杂志试试:

businessman$.next("寻秦记");
businessman$.next("射雕英雄传");

// logs:
// 小明收到寻秦记  
// 小刚收到寻秦记 
// 小明收到射雕英雄传  
// 小刚收到射雕英雄传

大家都收到了名著,皆大欢喜。 中间商最重要的当然是从出版社进货,然后再发货给消费者,看看是怎样表现的:

// 一个出版社
const playboy$ = from(["寻秦记", "射雕英雄传"]);
// 来了一个中间商
const businessman$ = new Subject();
// 中间商订阅了武侠
playboy$.subscribe(businessman$);
// 小明订阅了中间商
businessman$.subscribe({
	next: (v) => console.log("小明收到" + v)
});

// logs:
// 小明收到寻秦记
// 小明收到射雕英雄传

好的,我们现在遇到了我们的第一个操作符from。from可以将数组、promise 或迭代器转换成 observable。

此例中,我们将一个生产流数组转化成了一个出版社,他会有序生产数组中的产品。然后在有人订阅后发出。

此时会有一个疑惑,为什么没有发送(next),也能收(subscribe)到东西。

因为:

const playboy$ = from(["寻秦记", "射雕英雄传"]);

就相当于:

const playboy$ = new Observable((subscriber) => {
	subscriber.next("寻秦记");
	subscriber.next("射雕英雄传");
});

这就是操作符的作用,简化了你的工作。

当然订阅与发送的顺序也一定要注意,普通的订阅是收不到订阅之前的数据的,如下例:

const businessman$ = new Subject();
// 这个在subscrib之前,所以小明收不到
businessman$.next("寻秦记");
// 此时小明订阅,他错过了寻秦记
businessman$.subscribe({
	next: (v) => console.log("小明收到" + v)
});
// 只会发 射雕英雄传
businessman.next("射雕英雄传");

// logs: 
// 小明收到射雕英雄传

Subject 本质还是一个Observable, 但它既可以订阅,也可以发送,更加的灵活,更加多的适用场景。

BehaviorSubject

BehaviorSubject是我们状态管理器的关键性零件。

我们先来看看BehaviorSubject是什么。

看名字就知道,它其实是一个有能力的Subject。它的能力是:它永远会存一个最新的值。这个中间商发且只发最新的一期杂志。

// BehaviorSubject 必须有初始值
// 中间商手中第一期(初始值):寻秦记
const businessman$ = new BehaviorSubject("寻秦记");
// 小明订阅了
businessman$.subscribe({
	next: (v) => console.log("小明收到" + v)
});
// 中间商第二期:武侠周年版
businessman$.next("武侠周年版");
// 中间商第三期:射雕英雄传
businessman$.next("射雕英雄传");
// 小刚订阅了,只会收到最新的一期
businessman$.subscribe({
	next: (v) => console.log("小刚收到" + v)
});

// logs:
// 小明收到寻秦记
// 小明收到武侠周年版
// 小明收到射雕英雄传
// 小刚收到射雕英雄传

只要我订阅了,就总能接收到最新的数据,实时更新。这是不是超级契合我们前端的状态管理器,还是响应式的。

结语

RxJS的前期铺垫工作就完成了,下一章我们就开始围绕BehaviorSubject来搭建我们的状态管理器。

其它

文章和源码

本系列github地址

brass状态管理器

按本系列文章思路实现的响应式状态管理器: