什么是 RxJS
RxJS (Reactive Extensions For JavaScript) RxJS即Lodash for async,一个通过observable组合各种非同步行为的library。其中,Reactive 是指响应式编程(Reactive Programming)。
任何异步事件在响应式编程都是异步事件流。不仅仅是 click、hover 这种事件,任何变量、用户输入、属性、缓存、数据结构等,响应式编程把所有事物都看成是数据流。数据流是类似数组一样的序列,可以像数组一样,用 merge、map、concat 等方法操作。
Observable
一个序列,里面的元素会随着时间推送
- 在未被订阅之前不会送出元素
- 可被订阅
- 具有多种operators
var mouseOver = Observable.fromEvent(DOM, 'mouseover');
var subscription = mouseMove.subscribe((x) => console.log(x);
subscription.unsubscribe()
建立 Observable 的一些API:
- 单值:of, empty, never
- 多值:from
- 定时:interval, timer
- 从事件创建:fromEvent
- 从 Promise 创建:fromPromise
- 自定义创建:create
Observable.of(1,2,3)
Observable.from([2,3,4])
Observable.from(fetch('url'))
Observable.ajax('url')
Observable.fromEvent(DOM, 'click')
Observable.interval(1000)
// example
var sub = Observable.from([1,2,3])
.map(x => x+1)
.filter(x => x%2===0)
.subscribe({
next: x => console.log(x)
error: err => {}
complete: () => {}
})
Observable生产过程图示:
Observable就是一条生产线,生产线上的产品就是Observable的元素。第一个进行打包的机器手就类似于map操作符,它会对每个元素进行一层封装(纸盒包装),后面一个机器手对元素进行筛选,剔除掉不符合产品标准的元素,类似于filter操作符。生产线本来是静止的,启动生产线的工人就是observer这个角色。
Operator
- 是 Observable 的方法
- 可对元素作运算处理
- 永远回传一个新的 Observable(有例外)
异步事件流
上图点击事件流程:
- click 事件流
- 事件流产生的值
- 错误
- 事件流结束
- 时间轴
涉及到的RxJS基本概念:
Observable:点击事件流 Observers:捕获值/错误/事件结束的方法 Subscription:Observable产生的值需要通过subscription把值传给observers
为什么要用 RxJS
一个例子:页面上有一个按钮,现在需要统计按钮点击次数
普通写法:
var counter = 0;
document.getElementById("myBtn").addEventListener("click", function () {
counter = counter + 1;
});
RxJS 写法:
let button = document.getElementById("myBtn");
let clickStream$ = fromEvent(button, "click");
let counterStream$ = clickStream$.pipe(
map((data) => { return 1 }),
scan((acc, curr) => acc + curr, 0)
);
counterStream$.subscribe(data => {
console.log("this is the click counter: " + data);
});
整个事件流可以描述成:
clickStream: ---c----c--c----c------c-->
map(c becomes 1)
---1----1--1----1------1-->
scan(+)
counterStream: ---1----2--3----4------5-->
点击事件可以看成是数据流(clickStream),在 clickStream 事件流基础上用方法map把每次点击事件转化成1,然后用 scan把所有的点击次数加起来,当执行 map 或者 scan 的时候都会在原来的数据流基础上生产一个新的数据流,原来的数据流不变。