最近一直忙于工作,也没倒开时间写博客,组里技术leader让小编去做一次RxJS的技术分享,说时迟那时快果断就打开博客准备先写一遍中文版,之后译成英文版发到公司confluence上,话不多少,开始吧~
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bintitle>
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js">script>
head>
<body>
<input id="height" type="number">
body>
html>
const height = document.getElementById('height');
// 将Keyup事件变成Observable
// 约定俗成的写法会将流状的内容加一个$命名
const height$ = Rx.Observable.fromEvent(height, 'keyup');
height$.subscribe(val=> console.log(val.target.value + ' ' + new Date());
"1 Sun Jan 12 2020 14:24:06 GMT+0800 (中国标准时间)"
"12 Sun Jan 12 2020 14:24:07 GMT+0800 (中国标准时间)"
"123 Sun Jan 12 2020 14:24:07 GMT+0800 (中国标准时间)"
"1234 Sun Jan 12 2020 14:24:08 GMT+0800 (中国标准时间)"
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bintitle>
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js">script>
head>
<body>
<div>
<input id="length" type="number">
div>
<div>
<input id="width" type="number"/>
div>
<div id="area">div>
body>
html>
const length = document.getElementById('length');
const width = document.getElementById('width');
const area = document.getElementById('area');
// 将Keyup事件变成Observable
// 约定俗成的写法会将流状的内容加一个$命名
const length$ = Rx.Observable.fromEvent(length, 'keyup').pluck('target', 'value');
const width$ = Rx.Observable.fromEvent(width, 'keyup').pluck('target', 'value');
// 为了计算结果的话,需要进行合并
// combineLatest表示两个流中只要有一个有最新的值,就重新计算一遍
// zip 表示两个流都需要有新值出现,才会重新计算一次
const area$ = Rx.Observable.combineLatest(length$, width$, (l, w) => {
return l*w;
});
area$.subscribe(val => {
area.innerHTML = val
});
length: ----- 1 ------------- 3
width: ----------- 2 -------
area: ----------- (2,1) -- (2,3)
\ \
--------------2--------6------
// interval每隔1s发射一个值,从0开始,发射的是位置数
// take只保留前三个数据,就触发complete方法
const interval$ = Rx.Observable.interval(1000).take(3);
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
});
// timer的第一个参数是开始延迟多少毫秒发射,第二个参数是每次发射间隔是多少毫秒
// 如下事件会在开始后的2秒开始输出0,之后间隔1秒输出1 2 3 ...
// 如果只设置第一个参数则只会发射出一次
const timer$ = Rx.Observable.timer(2000, 1000)
timer$.subscribe(v=> console.log(v))
xxx.map(event=> event.target.value)
const a$ = Rx.Observable.fromEvent(length, 'keyup').mapTo(1);
// 相当于.map(_=>1)
const b$ = Rx.Observable.fromEvent(width, 'keyup').mapTo(2);
Rx.Observable.combineLatest(a$, b$, (a, b) => a*b);
// 不管流内的lenth/width怎么变化,a$的值都是1,b$的值的都是2
xxx.pluck('target', 'value')
// interval每隔1s发射一个值,从0开始,发射的是位置数
// do作为中间桥梁,可以做subscribe做的内容,因为subscribe之后我们就无法使用操作符再进行处理了
// take只保留前三个数据,就触发complete方法
const interval$ = Rx.Observable
.interval(1000)
.do( v => console.log(`当前值是:${v}`))
.take(3);
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
输出内容
"当前值是:0"
0
"当前值是:1"
1
"当前值是:2"
2
"Complete"
const interval$ = Rx.Observable
.interval(1000)
.filter( v => v%2===0) // 只保留是偶数的流数据
.scan((x,y) => { // x为上一个return的值
return x+y;
})
.map(x => x+1)
.take(4);
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
输出内容
1
3
7
13
"Complete"
const interval$ = Rx.Observable
.interval(1000)
.filter( v => v%2===0) // 只保留是偶数的流数据
.take(4)
.reduce((x,y) => { // x为上一个return的值
return x+y;
});
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
输出内容
12
"Complete"
// interval每隔1s发射一个值,从0开始,发射的是位置数
// filter过滤条件保留指定流内容
// do作为中间桥梁,可以做subscribe做的内容,因为subscribe之后我们就无法使用操作符再进行处理了
// take只保留前三个数据,就触发complete方法
const interval$ = Rx.Observable
.interval(1000)
.filter( v => v%2===0) // 只保留是偶数的流数据
.do( v => console.log(`当前值是:${v}`))
.take(3);
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
输出内容
"当前值是:0"
0
"当前值是:2"
2
"当前值是:4"
4
"Complete"
const interval$ = Rx.Observable
.interval(1000)
.filter( v => v%2===0) // 只保留是偶数的流数据
.do( v => console.log(`当前值是:${v}`))
.first();
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
输出内容
"当前值是:0"
0
"Complete"
const interval$ = Rx.Observable
.interval(1000)
.filter( v => v%2===0) // 只保留是偶数的流数据
.do( v => console.log(`当前值是:${v}`))
.skip(2);
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
输出内容[因为有do所以会输出 当前值是x 的内容,但没发射对应元素]
"当前值是:0"
"当前值是:2"
"当前值是:4"
4
"当前值是:6"
6
"当前值是:8"
8
"当前值是:10"
10
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bintitle>
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js">script>
head>
<body>
<div>
<input id="length" type="number">
div>
body>
html>
const length = document.getElementById('length');
// 使用debounceTime将2秒内的流发射过滤掉,保留最后的发射内容
// 即只有停下来了2秒了,内容才会输出
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value')
.debounceTime(2000);
// 相当于.debounce(()=> Rx.Observable.interval(300));
length$.subscribe(val => console.log(val));
输出内容
当输入停下2秒后,输出输入框中的内容
const length = document.getElementById('length');
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value')
.distinct();
length$.subscribe(val => console.log(val));
输出内容
在输入框中分别输入
1
12
123
12
1
1234
----------输出结果为----------
1
12
123
1234
-----即重复的内容不会输出
const length = document.getElementById('length');
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value')
.distinctUntilChanged();
length$.subscribe(val => console.log(val));
输出内容
在输入框中分别输入
1
12
123
123
12
123
----------输出结果为----------
1
12
123
12
123
-----即仅与流中上一个元素重复的内容不会输出
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bintitle>
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js">script>
head>
<body>
<div>
<input id="length" type="number">
<input id="width" type="number">
div>
body>
html>
const length = document.getElementById('length');
const width = document.getElementById('width');
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value');
const width$ = Rx.Observable
.fromEvent(width, 'keyup')
.pluck('target', 'value');
const merged$ = Rx.Observable
.merge(length$, width$);
merged$.subscribe(val => console.log(val));
输出内容
在输入框中先后输入
1 空
1 2
13 2
13 24
134 24
1344 24
--------------------输出结果-----------------------
"1"
"2"
"13"
"24"
"134"
"1344"
const length = document.getElementById('length');
const width = document.getElementById('width');
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value');
const width$ = Rx.Observable
.fromEvent(width, 'keyup')
.pluck('target', 'value');
const merged$ = Rx.Observable
.concat(length$, width$);
merged$.subscribe(val => console.log(val));
输出内容
在第一个框中输入的内容会一直输出到console中,第二个输入框中输入的内容会一直无法输出到console中
因为第一个框的事件是无穷的序列,所以第二个流永远无法执行到
const startWith$ = Rx.Observable
.from([1,2,3,4])
.startWith(0)
startWith$.subscribe(val => console.log(val));
输出内容
0
1
2
3
4
const length = document.getElementById('length');
const width = document.getElementById('width');
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value');
const width$ = Rx.Observable
.fromEvent(width, 'keyup')
.pluck('target', 'value');
const combineLatest$ = Rx.Observable
.combineLatest(length$, width$, (l, w)=> {
return l*w;
})
combineLatest$.subscribe(val => console.log(val));
输出结果
会根据两个输入框输入的内容即是获得相乘的结果
const length = document.getElementById('length');
const width = document.getElementById('width');
const length$ = Rx.Observable
.fromEvent(length, 'keyup')
.pluck('target', 'value');
const width$ = Rx.Observable
.fromEvent(width, 'keyup')
.pluck('target', 'value');
const zip$ = Rx.Observable
.zip(length$, width$, (l, w)=> {
return l*w;
})
zip$.subscribe(val => console.log(val));
const interval$ = Rx.Observable.interval(1000).take(3);
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
// Never状态如下,会一直发射,因为不知道流什么时候结束
const interval$ = Rx.Observable
.interval(1000)
.filter( v => v%2===0) // 只保留是偶数的流数据
.do( v => console.log(`当前值是:${v}`))
.last();
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
// 手动抛出error,并在error状态函数中捕获并处理
const interval$ = Rx.Observable
.interval(1000)
.map(v => {
throw '抛出异常'; // 此时就会在error中输出
})
.take(4)
.reduce((x,y) => { // x为上一个return的值
return x+y;
});
interval$.subscribe(next => {
console.log(next);
}, error => {
console.log(error);
}, complete => {
console.log('Complete');
})
// 通常用于测试当中,使用官方的方式来创建never / error / empty 流
// 官方自带的never
const never$ = Rx.Observable.never();
// 官方自带的throw error
const throw$ = Rx.Observable.throw('出错了');
// 官方自带的empty()调用后悔直接调用complete方法中的内容
const empty$ = Rx.Observable.empty();