持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天。点击查看活动详情
RxJS是ReactiveX编程理念的JavaScript版本。ReactiveX来自微软,它是一种针对异步数据流的编程。简单来说,它将一切数据,包括HTTP请求,DOM事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。RxJS是一种针对异步数据流编程工具,或者叫响应式扩展编程;Angular引入RxJS为了就是让异步可控、更简单。RxJS里面提供了很多模块。这里我们主要给大家讲RxJS里面最常用的Observable和fromEvent。
Observable
- 官方:表示一个概念,这个概念是一个可调用的未来值或事件的集合。
- 通俗:数据类型可以是 number 类型,也可以是 boolean 类型,而 Observable 也是一种类型.
- 一个 Observable 应该包含四个部分:创建、订阅、执行、清理
const observable$ = Observable.create(observer => {//创建observable
let i = 0;
observer.next(i);
setInterval(() => {
i++;
observer.next(i);//执行
}, 1000);
});
const subscription = observable$.subscribe(value => {//订阅observable
console.log(value) 1 2 3 4 5 6 7 8 9 10
if (value === 10) {
subscription.unsubscribe();//清理,即取消订阅
}
})
Observer
- 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
- 根据情况处理 Observable 发出的值.
- 观察值可以执行值的发射,其实观察值有三种发射方式. next、 error、 complete.
- next - 发送一个值
- error - 发送一个错误
- complete - 通知已完成,不再发射值
const observable$ = Observable.create((observer) => {
let i = 0;
observer.next(i);
setInterval(() => {
i++;
if (i === 10) {
observer.complete();
}
if (i === 11) {
//不会执行,因为在第10秒已经执行了complete
observer.error("finish");
}
observer.next(i);
}, 1000);
});
const _observer = {
next: (value) => console.log("收到一个值:" + value),
error: (err) => console.log("收到一个错误:" + err),
complete: () => console.log("已完成计时!"),
};
observable$.subscribe(_observer);
Subscription
- 表示 Observable 的执行,主要用于取消 Observable 的执行。
- 当你使用 subscribe()时,返回一个 Subscription 对象,该对象有一个 unsubscribe() 方法.
在 RxJS 中用来解决异步事件管理的的基本概念是:
- Observable (可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。
- Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
- Subscription (订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
- Operators (操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
- Subject : 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
- Schedulers (调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他。
Subject
Subject 是一种特殊类型的 Observable,它允许将值多播给多个观察者,所以 Subject 是多播的, 而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。 每个 Subject 都是观察者。 - Subject 是一个有如下方法的对象: next(v)、error(e) 和 complete() 要给 Subject 提供新值,只要调用 next(theValue),它会将值多播给已注册监听该 Subject 的观察者们。
import { Subject, from } from 'rxjs';
const subject = new Subject<number>();
subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
});
subject.next(1);
subject.next(2);
// Logs:
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2
因为 Subject 是观察者,这也就在意味着你可以把 Subject 作为参数传给任何 Observable 的 subscribe 方法
import { Subject, from } from 'rxjs';
const subject = new Subject<number>();
subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
});
const observable = from([1, 2, 3]);
observable.subscribe(subject);
// Logs:
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2
// observerA: 3
// observerB: 3
Operators (操作符)
采用函数式编程风格的纯函数 (pure function),使用像 map 、 filter 、 concat 、 flatMap 等这样的操作符来处理集合。
操作符就是 Observable 提供的方法.当你调用操作符时,Observable 并不会改变, 而且操作符会返回一个全新的 Observable.我们再次改造计时器的案例, 这次不再使用这么原始的方式,而是使用操作符来完成 Observable 的创建、延时等操作
const observable$ = timer(0, 1000).pipe(take(11));
observable$.subscribe(console.log);
timer:第一个参数是延时执行时间,第二个参数是间隔执行时间.自身会返回一个
Observable.timer(0,1000)是指延时 0 秒执行,每隔 1 秒发出一个值.他会从 0 开始发送,无限递增
pipe:管道,可以对一些操作符进行链式调用
take:指执行的次数. take(11)则只发送前 11 个值
Rxjs 异步数据流编
- 目前常见的异步编程的几种方法:
- 1)、回调函数
- 2)、事件监听/发布订阅
- 3)、
Promise - 4)、
Rxjs
Promise 和RxJS 处理异步对比
Promise处理异步:
let promise = new Promise((resolve) => {
setTimeout(() => {
resolve("---promise timeout---");
}, 2000);
});
promise.then((value) => console.log(value));
RxJS处理异步:
import { Observable } from "rxjs";
let stream = new Observable((observer) => {
setTimeout(() => {
observer.next("observable timeout");
}, 2000);
});
stream.subscribe((value) => console.log(value));
从上面列子可以看到RxJS 和Promise 的基本用法非常类似,除了一些关键词不同。Promise里面用的是then() 和resolve(),而RxJS 里面用的是next() 和subscribe()。
Promise 和RxJS 的用法基本相似。其实Rxjs 相比Promise 要强大很多。比如``Rxjs中可以中途撤回、Rxjs可以发射多个值、Rxjs` 提供了多种工具函数等等。
Rxjs 订阅后多次执行
- 如果我们想让异步里面的方法多次执行,比如下面代码。
- 这一点
Promise是做不到的,对于Promise来说,最终结果要么resole(兑现)、要么reject(拒绝),而且都只能触发一次。如果在同一个Promise对象上多次调用resolve方法,则会抛异常。而Observable不一样,它可以不断地触发下一个值,就像next()这个方法的名字所暗示的那样。
let promise = new Promise((resolve) => {
setInterval(() => {
resolve("---promise setInterval---");
}, 2000);
});
promise.then((value) => console.log(value));
Rxjs
let stream = new Observable<number>((observer) => {
let count = 0;
setInterval(() => {
observer.next(count++);
}, 1000);
});
stream.subscribe((value) => console.log("Observable>" + value));
Rxjs 延迟执行
dom转换成dom流,然后对整个dom流进行处理
import { Observable, fromEvent } from "rxjs";
import { map, filter, throttleTime } from "rxjs/operators";
var button = document.querySelector("button");
fromEvent(button, "click")
.pipe(throttleTime(1000))
.subscribe(() => console.log(`Clicked`));
catchError
// 发出错误
const source = throwError("This is an error!");
// 优雅地处理错误,并返回带有错误信息的 observable
const example = source.pipe(catchError((val) => of(`I caught: ${val}`)));
// 输出: 'I caught: This is an error'
const subscribe = example.subscribe((val) => console.log(val));
throwError
const result = concat(of(7), throwError("error"));
result.subscribe(
(x) => console.log(x),
(e) => console.error(e)
);