通过一个案例来理解回调地狱,通过 http 请求获取人、行星和星系,先找到人,然后是行星,最后是星系。这涉及三个异步操作的回调。如下每个回调内部依赖于其父级,这会导致回调地狱的’厄运金字塔’风格。
getPerson(person => {
getPlanet(person, (planet) => {
getGalaxy(planet, (galaxy) => {
console.log(galaxy)
})
})
})
在 RxJS 中通过 mergeMap 解决这个问题
getPerson()
.mergeMap(person => getPlanet(person))
.mergeMap(planet => getGalaxy(planet))
.subscribe(galaxy => console.log(galaxy))
如上,代码被扁平化并包含单个方法调用链,没有回调地狱的问题。
Promise 也是避免回调地狱的一种方式,其特点是无论有没有人关心它的执行结果,它都会立即开始执行,并且你没有机会取消这次执行。
相比 Promise ,Observable 可观察对象,能够在它变化时通知观察者。(Observable 负责生产数据,观察者负责消费数据)
基本概念:
可观察对象:Observable、Subject、BehaviorSubject、ReplaySubject
- ReplaySubject:新的订阅者会广播所有历史结果
- BehaviorSubject:创建 Observable 对象时可以传默认值,观察者订阅后会直接拿到默认值
数据流:从可观察对象内部输出的数据就是数据流
操作符:操作数据流,进行转换/过滤
辅助方法:返回 Observable 对象,可进行订阅
可观察对象的特性:
- Observable 对象内部可多次调用 next 方法
- Observable 对象内部调用 complete 方法终止
- Observable 内部逻辑错误,通过 error 方法发送给订阅者 observer.error(err)
- 可观察对象是惰性的,订阅后才会执行
- 可观察对象可以有 n 多订阅者
RxJS 操作符
辅助方法:from(args) 参数可以是数组/promise对象,生成 Observable 对象
forkJoin:类似 Promise.all 即所有 Observable 完成后才一次性返回值
forkJoin({
goods: from(axios.get(...)),
category: ...,
}).subscribe(console.log)
switchMap:切换可观察对象
点击事件:事件是一个可观察对象
fromEvent(button, 'click').pipe(
switchMap(event => interval(1000))
).subscribe(console.log)
take(2):获取数据流中的前几个
takeUntil:接收可观察对象,当可观察对象发出值时终止数据源
fromEvent(document, 'mouse').pipe(takeUntil(fromEvent(button, 'click')).subscribe()
combineLatest:任意 Observable 发出值时,发出每个 Observable 的最新值。多个 Observable 依靠彼此进行计算。
startWith:发出给定的第一个值
const source = of(1,2,3)
const example = source.pipe(startWith(0))
example.subscribe()
错误处理:catchError:返回一个 Observable 对象