首先我们要弄懂这几个问题:
1.rxjs是什么
2.rxjs能做什么
3.已经有了promise的情况下为什么还需要rxjs
4.rxjs的使用方法
如果这些问题都直接去网上搜然后贴上链接,感觉我这篇文章就没什么写的必要了。当然了资料已经非常多了,确实不需要我再为大家写一点所谓有帮助的文章了。那么为什么还要写呢,写这个是为了自己,为了自己能够更好的理解rxjs,与大家无关,也与白洁无关。
1.rxjs是什么
RxJS 是一个库,它通过使用 observable 序列来编写异步和基于事件的程序。它提供了一个核心类型 Observable,附属类型 (Observer、 Schedulers、 Subjects) 和受 [Array#extras] 启发的操作符 (map、filter、reduce、every, 等等),这些数组操作符可以把异步事件作为集合来处理。
2.rxjs能做什么
javascript写前端页面的时候,除了展示数据UI之外,还需要相应用户的操作,展示动态的数据,展示动态的UI。于是前端的异步有:事件(event)、ajax、动画(animation)、定时器(timer)。 处理这些的时候常见的问题有:异步的回调地狱(callback hell) 竞态条件(race condition) 内存泄漏(memory leak) 管理复杂状态(manage complex states) 错误处理(exception handling)
1.回调地狱:按照普通的javascript方法写,所有的处理写在某个事件的完成后的回调中,当有多个回调依次执行后1->2->3->4很容易将代码写成火箭形,很大一团根本没发改。
2.竞态条件:是指系统出现不恰当的执行时序,而得到不正确的结果。比如搜索框中,每次输入后发送请求获取结果展示在搜索框下面,由于网络或者后端查询的原因有可能导致最后发送的请求比之前的请求更快的完成了,这时最终展现的并不是最后那个请求的结果,而这并不是我们所希望的。
3.内存泄漏:当单页面应用切换页面时未在合适的时机移除监听事件造成内存泄漏
4.复杂状态的管理:异步带来了状态的改变,可能会使状态管理变得非常复杂,尤其是某个状态有多个来源时,比如有些应用,一开始有一个默认值,再通过 AJAX 获取初始状态,存储在 localStorage,之后通过 WebSocket 获取更新。这时查询状态可能是同步或者异步的,状态的变更可能是主动获取也可能是被动推送的,如果还有各种排序、筛选,状态管理将会更加复杂。
5.错误处理:javascript中的try catch只能捕获同步的错误,对于异步的错误难以获取。promise中可以使用一个全局的catch。
3.已经有了promise的情况下为什么还需要rxjs
Promise:promise已经解决了很多异步的难点,比如将回调地狱改为了链式调用,统一同步和异步代码,但是promise只有一个结果,并且不可以被提前取消(讲真,可能是我做的工作都太简单了,这些问题其实我并没有真正遇到过)
4.rxjs的使用方法
异步 API
各种异步的API
DOM Events
XMLHttpRequest
fetch
WebSocket
Service Worker
setTimeout
setInterval
requestAnimationFrame
如果使用rxjs来处理,可以使用统一的API,而且借助rxjs各种强大的操作符,可以非常简单的实现需求。对于不同的场景使用不同API来完成功能:
- 创建 Observable 的方法、types、schedulers 和一些工具方法
import { Observable, Subject, asapScheduler, pipe, of, from, interval, merge, fromEvent, SubscriptionLike, PartialObserver } from 'rxjs';
// asapScheduler SubscriptionLike PartialObserver 没有使用过
- 操作符(可以理解为rxjs提供的一些快捷功能,对Observe中的produce产生的数据的预处理,处理完成之后再到subscribe中的观察者中进行处理)
import { map, filter, scan, take, takeUtil } from 'rxjs/operators';
- webSocket
import { webSocket } from 'rxjs/webSocket';
4.ajax
import { ajax } from 'rxjs/ajax';
创建Observable
创建Observable主要有两步
- new Observable时接受一个产生数据的方法function,function产生数据的方式为function接受一个形参(ob)ob有三个属性:next,error,complete。在方法内使用ob.next('希望传出的值'),来向外面传输流。
- new Observable后返回一个对象,这个对象一般使用$作为后缀便于标识,在这个对象上调用subscribe方法传入你所希望的观察者函数。
import { Observable } from 'rxjs';
const source$ = new Observable(observer => {
let number = 1
setInterval(() => {
observer.next(number++)
}, 1000)
})
const observer = {
next : item => console.log(item)
}
console.log('start')
source$.subscribe(observer)
console.log('end')
- 对数据流的预处理,这是两步之外的,但还是希望一起讲。对数据的预处理,new Observable产生的发出数据流对象之前,可以调用pipe方法来对数据进行预处理叫做Operators操作符。注意⚠️,每一个操作符都会返回一个全新的Observable对象
source$.pipe(
take(5), // 只要前五个
first(), // 是获得满足判断条件的第一个数据
)
要实现的功能
- 实现类似promise的功能,单个的Promise.then()
可以使用concatMap操作符
new Observable((observe) => {
setTimeout(() => observe.next(['first']), 1000)
}).pipe(
concatMap(value => {
console.log(value);
return new Observable((observe) => {
setTimeout(() => observe.next(value.concat('two')), 1000)
})
}),
).subscribe()
2.
实现类似promise的链式调用
使用concatMap,具体写法类似
from(this.getUserInfo())
.pipe(
concatMap(userInfo => this.getUserParent(userInfo)),
concatMap(parentInfo => this.get(...))
)
3.实现类似promise.all的效果
forkJoin()
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。