假如当初有一个简略的工作:页面上有一个按钮,当你点击按钮的时候,须要启动一个定时器。应用 RxJS 咱们能够能够很不便地实现上述性能:
尽管以上代码可能失常运行,但仍存在两个问题:
存在相似于回调地区的问题。咱们必须手动解决每个订阅。
接下来让咱们来介绍一下高阶 observable 及如何利用它使得事件变得更简略。
高阶 Observables
一个 Observable 对象能够收回任何类型的值:数值、字符串、对象等等。这意味着 Observable 对象也能够收回 Observable 类型的值。
与 JavaScript 高阶函数相似,一个高阶的 Observable 示意一个 Observable 对象外部会返回另一个 Observable 对象。此时咱们来更新一下下面的示例,以便更加直观的理解上述概念:
import {fromEvent, interval} from ‘rxjs’;
import {map} from ‘rxjs/operators’;
const button = document.querySelector(‘button’);
const click$ = fromEvent(button, ‘click’);
const interval$ = interval(1000);
const clicksToInterval$ = click$.pipe(map(event => {
return interval$;
}));
clicksToInterval$.subscribe(intervalObservable =>
console.log(intervalObservable)
);
当用户点击按钮时,咱们的 map 操作符将返回一个 interval observable 对象。当咱们订阅 clicksToInterval$ 对象时,将收回 intervalObservable 对象。
在你订阅 clicksToInterval$ 对象时,控制台输入的是 intervalObservable 对象。这里须要记住的是,observable 对象是 lazy 的,如果想要从一个 observable 对象中获取值,你必须执行订阅操作,比方:
clicksToInterval$.subscribe(intervalObservable => {
intervalObservable.subscribe(num => {
console.log(num);
});
});
在介绍高阶 observable 对象的概念之后,接下来让咱们来介绍两个有用的操作符,用来帮忙咱们解决下面提到的问题。
mergeAll
When the inner observable emits, let me know by merging the value to the outer observable.
mergeAll() 操作符底层做的操作跟下面的例子一样,它获取 inner observable 对象,执行订阅操作,而后把值推给 observer(观察者)对象。
import {fromEvent, interval} from ‘rxjs’;
import {map, mergeAll} from ‘rxjs/operators’;
const click$ = fromEvent(button, ‘click’);
const interval$ = interval(1000);
const observable$ = click$.pipe(map(event => {
return interval$;
}));
observable$.mergeAll().subscribe(num => console.log(num));
在下面的示例中,source observable 对象是 clicks$ observable 对象,而 inner observable 对象是 interval$ observable 对象。
在 RxJS 中这是一个通用的模式,因而有一个快捷方式来实现雷同的行为 —— mergeMap():
mergeMap() <=> map() + mergeAll()
const button = document.querySelector(‘button’);
const click$ = fromEvent(button, ‘click’);
const interval$ = interval(1000);
const observable$ = click$.pipe(mergeMap(event => {
return interval$;
}));
observable$.subscribe(num => console.log(num));
在下面的代码中,每当咱们点击按钮,咱们都会调用 interval$ 对象的 subscribe() 办法,这将导致在咱们的页面中会存在多个独立的定时器。如果这是你冀望实现的性能,那就没问题。但如果你只想放弃一个数据源,你就须要应用 switch() 操作符。
switch
Like mergeMap() but when the source observable emits cancel any previous subscriptions of the inner observable.
switch() 用于勾销前一个订阅,并切换至新的订阅。如果咱们把代码更新为 switch() 操作符,当咱们屡次点击按钮时,咱们能够看到每次点击按钮时,咱们将获取新的 interval 对象,而上一个 interval 对象将会被主动勾销。
const button = document.querySelector(‘button’);
const click$ = fromEvent(button, ‘click’);
const interval$ = interval(1000);
const observable$ = click$.pipe(
map(event => {
return interval$;
}),
switchAll()
);
observable$.subscribe(num => console.log(num));
正如你说看到的,当点击三次按钮后,咱们仅有一个 interval 对象。反之,应用 merge() 操作符,咱们会有三个独立的 interval 对象。当源收回新值后,switch 操作符会对上一个外部的订阅对象执行勾销订阅操作。
在 RxJS 中这也是一个通用的模式,因而也有一个快捷方式来实现雷同的行为 —— switchMap():
switchMap() <=> map() + switch()
const button = document.querySelector(‘button’);
const click$ = fromEvent(button, ‘click’);
const interval$ = interval(1000);
const observable$ = click$.pipe(
switchMap(event => {
return interval$;
})
);
observable$.subscribe(num => console.log(num));
本文由博客一文多发平台 OpenWrite 公布!