web前端RxJS初步学习
来源:互联网 发布:网络管理视频教程下载 编辑:程序博客网 时间:2024/05/17 02:38
RxJS(Reactive Extensions for JavaScript) js响应式扩展
初学RxJS
http://cn.rx.js.org/manual/overview.html 中文网
https://zhuanlan.zhihu.com/p/23464709 demo网站
https://www.gitbook.com/book/buctwbzs/rxjs/details 比较好用初学者的网站
Observable (可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。(核心类型)
Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
Subscription (订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
Operators (操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
Subject (主体): 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
Schedulers (调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他
原生写法
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));//每次点击都会出现一个Clicked!
Rx写法
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.subscribe(() => console.log('Clicked!'))//每次点击都会出现一个Clicked! 事件触发.subscribe
原生写法
var count = 0; //全局变量可能引起代码污染(变量冲突)
var button = document.querySelector('button');
button.addEventListener('click', () => console.log(`Clicked ${++count} times`));
Rx写法 //纯净性 (Purity)
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.scan(count => count + 1, 0) //类似与reduce 获取上次的count 继续进行下一次操作 默认值0
.subscribe(count => console.log(`Clicked ${count} times`));
原生写法 一秒钟最多点一次
var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;//刚加载时记录时间
var button = document.querySelector('button');
button.addEventListener('click', () => {
if (Date.now() - lastClick >= rate) {
console.log(`Clicked ${++count} times`);
lastClick = Date.now();//点击时记录时间作为下一次点击时判断时间
}
});
Rx写法(RxJS 提供了一整套操作符来帮助你控制事件如何流经 observables ) //流动性 (Flow)
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)//一秒只能点击一次
.scan(count => count + 1, 0)//每次回调函数运行后的返回值会作为下次回调函数运行时的参数。
.subscribe(count => console.log(`Clicked ${count} times`)); //点击时触发
原生写法 (获取值) //限制每秒只能点击一次并且 计算conut的值
var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;
var button = document.querySelector('button');
button.addEventListener('click', (event) => {
if (Date.now() - lastClick >= rate) {
count += event.clientX;
console.log(count)
lastClick = Date.now();
}
});
Rx写法
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000) //限制每秒一次
.map(event => event.clientX) //计算值
.scan((count, clientX) => count + clientX, 0)
.subscribe(count => console.log(count));
func.call() 意思是 "同步地给我一个值"
observable.subscribe() 意思是 "给我任意数量的值,无论是同步还是异步"
创建 Observables Rx.Observable.create
var observable = Rx.Observable.create(function subscribe(observer) {
var id = setInterval(() => {
observer.next('hi')
}, 1000);
});
订阅 Observables
observable.subscribe(x => console.log(x));
执行 Observables
"Next" 通知: 发送一个值,比如数字、字符串、对象,等等。
"Error" 通知: 发送一个 JavaScript 错误 或 异常。
"Complete" 通知: 不再发送任何值。
清理 Observables
Subscription 表示进行中的执行,它有最小化的 API 以允许你取消执行。想了解更多订阅相关的内容,
请参见 Subscription 类型。使用 subscription.unsubscribe() 你可以取消进行中的执行:
var observable = Rx.Observable.from([10, 20, 30]);
var subscription = observable.subscribe(x => console.log(x));
// 稍后:
subscription.unsubscribe();
Subject (主体)多播
它允许将值多播给多个观察者,所以 Subject 是多播的,而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。
在下面的示例中,我们为 Subject 添加了两个观察者,然后给 Subject 提供一些值:
var subject = new Rx.Subject();
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(1);
subject.next(2);
observerA: 1
observerB: 1
observerA: 2
observerB: 2
因为 Subject 是观察者,这也就在意味着你可以把 Subject 作为参数传给任何 Observable 的 subscribe 方法,如下面的示例所展示的:
var subject = new Rx.Subject();
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
var observable = Rx.Observable.from([1, 2, 3]);
observable.subscribe(subject); // 你可以提供一个 Subject 进行订阅
observerA: 1
observerB: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3
引用计数
手动调用 connect() 并处理 Subscription 通常太笨重。通常,当第一个观察者到达时我们想要自动地连接,
而当最后一个观察者取消订阅时我们想要自动地取消共享执行。
请考虑以下示例,下面的列表概述了 Subscriptions 发生的经过:
第一个观察者订阅了多播 Observable
多播 Observable 已连接
next 值 0 发送给第一个观察者
第二个观察者订阅了多播 Observable
next 值 1 发送给第一个观察者
next 值 1 发送给第二个观察者
第一个观察者取消了多播 Observable 的订阅
next 值 2 发送给第二个观察者
第二个观察者取消了多播 Observable 的订阅
多播 Observable 的连接已中断(底层进行的操作是取消订阅)
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var multicasted = source.multicast(subject);
var subscription1, subscription2, subscriptionConnect;
subscription1 = multicasted.subscribe({
next: (v) => console.log('observerA: ' + v)
});
// 这里我们应该调用 `connect()`,因为 `multicasted` 的第一个
// 订阅者关心消费值
subscriptionConnect = multicasted.connect();//第一个观察者到达时连接
setTimeout(() => {
subscription2 = multicasted.subscribe({
next: (v) => console.log('observerB: ' + v)
});
}, 600);
setTimeout(() => {
subscription1.unsubscribe();
}, 1200);
// 这里我们应该取消共享的 Observable 执行的订阅,
// 因为此后 `multicasted` 将不再有订阅者
setTimeout(() => {
subscription2.unsubscribe();
subscriptionConnect.unsubscribe(); // 用于共享的 Observable 执行
}, 2000);
如果不想显示调用 connect(),我们可以使用 ConnectableObservable 的 refCount() 方法(引用计数),这个方法返回 Observable,
这个 Observable 会追踪有多少个订阅者。当订阅者的数量从0变成1,它会调用 connect() 以开启共享的执行。当订阅者数量从1变成0时,
它会完全取消订阅,停止进一步的执行。
refCount 的作用是,当有第一个订阅者时,多播 Observable 会自动地启动执行,而当最后一个订阅者离开时,多播 Observable 会自动地停止执行。
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var refCounted = source.multicast(subject).refCount();
var subscription1, subscription2, subscriptionConnect;
// 这里其实调用了 `connect()`,
// 因为 `refCounted` 有了第一个订阅者
console.log('observerA subscribed');
subscription1 = refCounted.subscribe({
next: (v) => console.log('observerA: ' + v)
});
setTimeout(() => {
console.log('observerB subscribed');
subscription2 = refCounted.subscribe({
next: (v) => console.log('observerB: ' + v)
});
}, 600);
setTimeout(() => {
console.log('observerA unsubscribed');
subscription1.unsubscribe();
}, 1200);
// 这里共享的 Observable 执行会停止,
// 因为此后 `refCounted` 将不再有订阅者
setTimeout(() => {
console.log('observerB unsubscribed');
subscription2.unsubscribe();
}, 2000);
observerA subscribed//刚进入就被调用
observerA: 0//500ms
observerB subscribed//1000ms
observerA: 1//1000ms
observerB: 1/1000ms
observerA unsubscribed//1500ms
observerB: 2//1500ms
observerB unsubscribed//2000ms
Subject 的其中一个变体就是 BehaviorSubject,它有一个“当前值”的概念。它保存了发送给消费者的最新值。
并且当有新的观察者订阅时,会立即从 BehaviorSubject 那接收到“当前值”。
在下面的示例中,BehaviorSubject 使用值0进行初始化,当第一个观察者订阅时会得到0。第二个观察者订阅时会得到值2,尽管它是在值2发送之后订阅的。
var subject = new Rx.BehaviorSubject(0); // 0是初始值
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.next(1);
subject.next(2);
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(3);
observerA: 0
observerA: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3
ReplaySubject 记录 Observable 执行中的多个值并将其回放给新的订阅者。
当创建 ReplaySubject 时,你可以指定回放多少个值:
var subject = new Rx.ReplaySubject(3); // 为新的订阅者缓冲3个值
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(5);
observerA: 1
observerA: 2
observerA: 3
observerA: 4
observerB: 2
observerB: 3
observerB: 4// 2 3 4 缓冲的三个值
observerA: 5
observerB: 5
Scheduler (调度器)
什么是调度器? - 调度器控制着何时启动 subscription 和何时发送通知。它由三部分组成:
调度器是一种数据结构。 它知道如何根据优先级或其他标准来存储任务和将任务进行排序。
调度器是执行上下文。 它表示在何时何地执行任务(举例来说,立即的,或另一种回调函数机制(比如 setTimeout 或 process.nextTick),或动画帧)。
调度器有一个(虚拟的)时钟。 调度器功能通过它的 getter 方法 now() 提供了“时间”的概念。在具体调度器上安排的任务将严格遵循该时钟所表示的时间。
var observable = Rx.Observable.create(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
})
.observeOn(Rx.Scheduler.async);
console.log('just before subscribe');
observable.subscribe({
next: x => console.log('got value ' + x),
error: err => console.error('something wrong occurred: ' + err),
complete: () => console.log('done'),
});
console.log('just after subscribe');
just before subscribe
just after subscribe
got value 1
got value 2
got value 3
done
async 调度器操作符使用了 setTimeout 或 setInterval,即使给定的延迟时间为0。
初学RxJS
http://cn.rx.js.org/manual/overview.html 中文网
https://zhuanlan.zhihu.com/p/23464709 demo网站
https://www.gitbook.com/book/buctwbzs/rxjs/details 比较好用初学者的网站
Observable (可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。(核心类型)
Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
Subscription (订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
Operators (操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
Subject (主体): 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
Schedulers (调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他
原生写法
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));//每次点击都会出现一个Clicked!
Rx写法
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.subscribe(() => console.log('Clicked!'))//每次点击都会出现一个Clicked! 事件触发.subscribe
原生写法
var count = 0; //全局变量可能引起代码污染(变量冲突)
var button = document.querySelector('button');
button.addEventListener('click', () => console.log(`Clicked ${++count} times`));
Rx写法 //纯净性 (Purity)
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.scan(count => count + 1, 0) //类似与reduce 获取上次的count 继续进行下一次操作 默认值0
.subscribe(count => console.log(`Clicked ${count} times`));
原生写法 一秒钟最多点一次
var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;//刚加载时记录时间
var button = document.querySelector('button');
button.addEventListener('click', () => {
if (Date.now() - lastClick >= rate) {
console.log(`Clicked ${++count} times`);
lastClick = Date.now();//点击时记录时间作为下一次点击时判断时间
}
});
Rx写法(RxJS 提供了一整套操作符来帮助你控制事件如何流经 observables ) //流动性 (Flow)
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)//一秒只能点击一次
.scan(count => count + 1, 0)//每次回调函数运行后的返回值会作为下次回调函数运行时的参数。
.subscribe(count => console.log(`Clicked ${count} times`)); //点击时触发
原生写法 (获取值) //限制每秒只能点击一次并且 计算conut的值
var count = 0;
var rate = 1000;
var lastClick = Date.now() - rate;
var button = document.querySelector('button');
button.addEventListener('click', (event) => {
if (Date.now() - lastClick >= rate) {
count += event.clientX;
console.log(count)
lastClick = Date.now();
}
});
Rx写法
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000) //限制每秒一次
.map(event => event.clientX) //计算值
.scan((count, clientX) => count + clientX, 0)
.subscribe(count => console.log(count));
func.call() 意思是 "同步地给我一个值"
observable.subscribe() 意思是 "给我任意数量的值,无论是同步还是异步"
创建 Observables Rx.Observable.create
var observable = Rx.Observable.create(function subscribe(observer) {
var id = setInterval(() => {
observer.next('hi')
}, 1000);
});
订阅 Observables
observable.subscribe(x => console.log(x));
执行 Observables
"Next" 通知: 发送一个值,比如数字、字符串、对象,等等。
"Error" 通知: 发送一个 JavaScript 错误 或 异常。
"Complete" 通知: 不再发送任何值。
清理 Observables
Subscription 表示进行中的执行,它有最小化的 API 以允许你取消执行。想了解更多订阅相关的内容,
请参见 Subscription 类型。使用 subscription.unsubscribe() 你可以取消进行中的执行:
var observable = Rx.Observable.from([10, 20, 30]);
var subscription = observable.subscribe(x => console.log(x));
// 稍后:
subscription.unsubscribe();
Subject (主体)多播
它允许将值多播给多个观察者,所以 Subject 是多播的,而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。
在下面的示例中,我们为 Subject 添加了两个观察者,然后给 Subject 提供一些值:
var subject = new Rx.Subject();
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(1);
subject.next(2);
observerA: 1
observerB: 1
observerA: 2
observerB: 2
因为 Subject 是观察者,这也就在意味着你可以把 Subject 作为参数传给任何 Observable 的 subscribe 方法,如下面的示例所展示的:
var subject = new Rx.Subject();
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
var observable = Rx.Observable.from([1, 2, 3]);
observable.subscribe(subject); // 你可以提供一个 Subject 进行订阅
observerA: 1
observerB: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3
引用计数
手动调用 connect() 并处理 Subscription 通常太笨重。通常,当第一个观察者到达时我们想要自动地连接,
而当最后一个观察者取消订阅时我们想要自动地取消共享执行。
请考虑以下示例,下面的列表概述了 Subscriptions 发生的经过:
第一个观察者订阅了多播 Observable
多播 Observable 已连接
next 值 0 发送给第一个观察者
第二个观察者订阅了多播 Observable
next 值 1 发送给第一个观察者
next 值 1 发送给第二个观察者
第一个观察者取消了多播 Observable 的订阅
next 值 2 发送给第二个观察者
第二个观察者取消了多播 Observable 的订阅
多播 Observable 的连接已中断(底层进行的操作是取消订阅)
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var multicasted = source.multicast(subject);
var subscription1, subscription2, subscriptionConnect;
subscription1 = multicasted.subscribe({
next: (v) => console.log('observerA: ' + v)
});
// 这里我们应该调用 `connect()`,因为 `multicasted` 的第一个
// 订阅者关心消费值
subscriptionConnect = multicasted.connect();//第一个观察者到达时连接
setTimeout(() => {
subscription2 = multicasted.subscribe({
next: (v) => console.log('observerB: ' + v)
});
}, 600);
setTimeout(() => {
subscription1.unsubscribe();
}, 1200);
// 这里我们应该取消共享的 Observable 执行的订阅,
// 因为此后 `multicasted` 将不再有订阅者
setTimeout(() => {
subscription2.unsubscribe();
subscriptionConnect.unsubscribe(); // 用于共享的 Observable 执行
}, 2000);
如果不想显示调用 connect(),我们可以使用 ConnectableObservable 的 refCount() 方法(引用计数),这个方法返回 Observable,
这个 Observable 会追踪有多少个订阅者。当订阅者的数量从0变成1,它会调用 connect() 以开启共享的执行。当订阅者数量从1变成0时,
它会完全取消订阅,停止进一步的执行。
refCount 的作用是,当有第一个订阅者时,多播 Observable 会自动地启动执行,而当最后一个订阅者离开时,多播 Observable 会自动地停止执行。
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var refCounted = source.multicast(subject).refCount();
var subscription1, subscription2, subscriptionConnect;
// 这里其实调用了 `connect()`,
// 因为 `refCounted` 有了第一个订阅者
console.log('observerA subscribed');
subscription1 = refCounted.subscribe({
next: (v) => console.log('observerA: ' + v)
});
setTimeout(() => {
console.log('observerB subscribed');
subscription2 = refCounted.subscribe({
next: (v) => console.log('observerB: ' + v)
});
}, 600);
setTimeout(() => {
console.log('observerA unsubscribed');
subscription1.unsubscribe();
}, 1200);
// 这里共享的 Observable 执行会停止,
// 因为此后 `refCounted` 将不再有订阅者
setTimeout(() => {
console.log('observerB unsubscribed');
subscription2.unsubscribe();
}, 2000);
observerA subscribed//刚进入就被调用
observerA: 0//500ms
observerB subscribed//1000ms
observerA: 1//1000ms
observerB: 1/1000ms
observerA unsubscribed//1500ms
observerB: 2//1500ms
observerB unsubscribed//2000ms
Subject 的其中一个变体就是 BehaviorSubject,它有一个“当前值”的概念。它保存了发送给消费者的最新值。
并且当有新的观察者订阅时,会立即从 BehaviorSubject 那接收到“当前值”。
在下面的示例中,BehaviorSubject 使用值0进行初始化,当第一个观察者订阅时会得到0。第二个观察者订阅时会得到值2,尽管它是在值2发送之后订阅的。
var subject = new Rx.BehaviorSubject(0); // 0是初始值
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.next(1);
subject.next(2);
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(3);
observerA: 0
observerA: 1
observerA: 2
observerB: 2
observerA: 3
observerB: 3
ReplaySubject 记录 Observable 执行中的多个值并将其回放给新的订阅者。
当创建 ReplaySubject 时,你可以指定回放多少个值:
var subject = new Rx.ReplaySubject(3); // 为新的订阅者缓冲3个值
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(5);
observerA: 1
observerA: 2
observerA: 3
observerA: 4
observerB: 2
observerB: 3
observerB: 4// 2 3 4 缓冲的三个值
observerA: 5
observerB: 5
Scheduler (调度器)
什么是调度器? - 调度器控制着何时启动 subscription 和何时发送通知。它由三部分组成:
调度器是一种数据结构。 它知道如何根据优先级或其他标准来存储任务和将任务进行排序。
调度器是执行上下文。 它表示在何时何地执行任务(举例来说,立即的,或另一种回调函数机制(比如 setTimeout 或 process.nextTick),或动画帧)。
调度器有一个(虚拟的)时钟。 调度器功能通过它的 getter 方法 now() 提供了“时间”的概念。在具体调度器上安排的任务将严格遵循该时钟所表示的时间。
var observable = Rx.Observable.create(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
})
.observeOn(Rx.Scheduler.async);
console.log('just before subscribe');
observable.subscribe({
next: x => console.log('got value ' + x),
error: err => console.error('something wrong occurred: ' + err),
complete: () => console.log('done'),
});
console.log('just after subscribe');
just before subscribe
just after subscribe
got value 1
got value 2
got value 3
done
async 调度器操作符使用了 setTimeout 或 setInterval,即使给定的延迟时间为0。
阅读全文
0 0
- web前端RxJS初步学习
- web前端初步学习的自我总结
- Rxjs学习
- RxJS 入门指引和初步应用
- Ngrx、RxJs、Redux的初步探究
- Web前端初步——札记0
- Web前端初步——札记1
- Web前端初步——布局0
- Web前端初步——Javascript(0)
- Web前端初步——HTML5
- RxJS
- RXJS
- RxJS
- 什么是Web前端?Web前端学习什么?
- web前端学习博客
- web前端学习
- Web前端技术学习
- web 前端学习
- Python 简介
- 3DSlicer24:Module-Create Scripted
- 8.23模拟赛
- 在QT实现文件传输
- STL学习笔记——关联式容器(二级容器)
- web前端RxJS初步学习
- LintCode-----31.数组划分
- HDU 5893List wants to travel(树链剖分-区间合并-区间更新-入边)
- log4j 详细讲解
- unity3d 5.6烘焙教程 持续更新中
- 如何把JAVA程序做成Windows服务,并开机运行
- 断点续传大文件,视频
- GitHub上传代码的方法以及出现的一些错误的解决办法
- 水题:UVa489-Hangman Judge