Commit 57e7604b by zerozou

Add 2017.8.29 log:RxJS

parent b1b2120d
# 2017/8/29
## RxJS
* 通过使用 observable 序列来编写异步和基于事件的程序
注册事件监听器的常规写法
```javascript
let button = document.querySelector('button')
button.addEventListener('click', () => console.log('clicked'))
```
使用Rx创建一个Observable来写
```javascript
let button = document.querySelector('button')
Rx.Observable.fromEvent(button, 'click')
.subscribe(() => console.log('clicked'))
```
* RxJS的优势
*纯净性(Purity)*
使用纯函数来产生值,常规的可能会共享外部变量写出一个非纯函数,增加出错率
```javascript
// 常规写法
let button = document.querySelector('button')
let count = 0
button.addEventListener('click', () => console.log(`clicked ${++count}`))
// RxJS写法
Rx.Observable.fromEvent(button, 'click')
.scan(count => count + 1, 0)
.subscribe(count => console.log(`clicked ${count}`))
```
`scan` 操作符的原理和 `reduce` 类似,需要给回调函数一个初始值,每次回调函数的返回值会作为下次回调函数的参数
*流动性(Flow)*
RxJS提供一套操作符来帮助我们控制事件如何流经Observable
```javascript
// 控制1s内最多点击一次
// 常规写法
let button = document.querySelector('button')
let count = 0
let rate = 1000
let lastClick = Date.now() - rate
button.addEventListener('click', () => {
if (Date.now() - lastClick >= rate) {
console.log(`clicked ${++count}`)
lastClick = Date.now()
}
})
// RxJS写法
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)
.scan(count => count + 1, 0
.subscribe(count => console.log(`clicked ${count}`))
```
*值(Values)*
RxJS可以转换流经Observable的值
```javascript
// RxJS写法
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)
.map(event => event.clientX)
.scan((count, clientX) => count + clientX, 0)
.subscribe(count => console.log(`clicked ${count}`))
```
* Observable
订阅Observable与调用函数类似,但是Observable可以随着时间推移“返回”多个值,这是函数做不到的。
Observables是同步执行的
```javascript
let observable = Rx.Observable.create(observer => {
console.log('Hello')
observer.next(42)
})
console.log('before')
observable.subscribe(x => console.log(x))
console.log('after')
/*
* before
* hello
* 42
* after
*/
```
可同步“返回”值也可异步“返回”值
```javascript
let observable = Rx.Observable.create(observer => {
observer.next(1)
setTimeout(() => {
observer.next(2)
}, 1000)
})
console.log('before')
observable.subscribe(x => console.log(x))
console.log('after')
/*
* before
* 1
* after
* 2
*/
```
*创建Observables*
Rx.Observable.create是Observable构造函数的别名,并接受一个名为subscribe的函数
下例创建一个Observable,并每隔一秒向观察者发送字符串‘hi’
```javascript
let observable = Rx.Observable.create(function subscribe(observer) {
setInterval(() => {
observer.next('hi')
}, 1000)
})
```
*订阅Observables*
可以如下订阅
```javascript
observable.subscribe(x => console.log(x))
```
`observable.subscribe``Observable.create(function subscribe(observer){ ... })` 是不同的,但从实际角度出发,概念是相同的
这表明 `subscribe` 调用在同一 Observable 的多个观察者之间是不共享的。
*执行Observables*
`Observable.create(function subscribe(observer){ ... })` 中的...代码表示Observable执行,惰性运算,只有在每个观察者被订阅后才会执行。随时间推移,执行会以同步或者异步产生一个或多个值。
Observable执行可以传递三种类型的值:
* “Next”通知:发送一个值(数字,字符串,对象……)
* “Error”通知:发送一个错误或异常
* “Complete”通知:不再发送值
“Error”和“Complete”只会在Observable执行期间发生一次,并且只会发生其中一个
*清理Observable执行*
当调用了 `observable.subscribe` ,观察者会被附加到新创建的Observable执行中,这个返回一个 `Subscription` 对象
```javascript
let subscription = observerable.subscribe(x => console.log(x))
```
可以使用这个对象调用 `unsubscribe` 方法来清Observable执行
```javascript
let observable = Rx.Observable.from([10, 20, 30])
let subscription = observable.subscribe(x => console.log(x))
// 稍后:
subscription.unsubscribe()
```
当使用 `create()` 创建Observable时,Observable必须定义如何清理执行的资源,你可以通过在 `function subscribe(){ ... }` 中返回一个自定义的 `unsubscribe` 函数
```javascript
let observable = Rx.Observable.create(function subscribe(observer) {
let intervalId = setTimeInterval(() => {
observer.next('hi')
}, 1000)
return function unsubscribe() {
clearInterval(intervalId)
}
})
```
* Observer
Observer是由Observable发送的值的消费者,一组回调函数的集合,每个回调函数对应不同的通知类型 `next``error``complete`
```javascript
let observer = {
next: x => console.log(`next ${x}`),
error: err => console.error(`error ${err}`),
complete: () => console.log('complete'),
}
```
Observer可以只有部分回调函数,Observable能正常执行,只是会忽略掉某些通知类型。
当订阅Observable的时候,可以只传一个回调函数作为参数,而并没有将其附加到观察者对象上。
```javascript
observable.subscribe(x => console.log(x))
```
在 observable.subscribe 内部,它会创建一个观察者对象并使用第一个回调函数参数作为 next 的处理方法。所有三种类型的回调函数都可以直接作为参数来提供:
```javascript
observable.subscribe(
x => console.log(x),
err => console.error(err),
() => console.log('complete')
)
```
* Subscription
Subscription表示可清理资源的对象,通常是Observable的执行。
Subscription三个方法:
*`unsubscribe`* 用来清理Observable的执行
```javascript
let observable = Rx.Observable.interval(1000)
let subscription = observable.subscribe(x => console.log(x))
subscription.unsubscribe()
```
*`add`* 把Subscription组合在一起,可以同时取消多个订阅
```javascript
let observable1 = Rx.Observable.interval(1000)
let observable2 = Rx.Observable.interval(2000)
let subscription1 = observable1.subscribe(x => console.log(x))
let subscription2 = observable2.subscribe(x => console.log(x))
subscription1.add(subscription2)
subscription1.unsubscribe()
```
*`remove`* 用来撤销已添加的Subscription
```javascript
subscription1.remove(subscription2)
```
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment