背景一:当前项目引用了tinyMce以及公式编辑器,在实际的使用中发现,有些题目可能需要较长的时候来填写。由于填写的时间超出了cookie的过期时间,所以当用户千辛万苦的填写完以后,点击保存按钮时发生了401。再回来原来的界面,一切归0。虽然当前已经采用了类似于github的处理方式,但由于在添加、编辑题目时的特殊性,实际的体验并不好。
背景二:当前项目对安全性要求比较高,我们希望10分钟内如果没有监测到用户的操作记录的话,进行锁屏的处理。
虽然在没有充分的使用Rxjs之前,该功能也能够实现,但Rxjs的防抖与节流功能可以更简单的满足上述需求。
节流 throttleTime
为了解决背景一,我们提出了新的想法:用户编辑tinyMce的内容时,组件使用了特定的方法进行接收。在这个接收方法中,我们记录最新接收值的时间,并去对应触发后台的心跳方法。这样以来,就保障了用户在编辑内容时充分地与后台进行交互,而不会在保存时由于过长时间未与后台交互发生的401问题了。
而此方法虽然能够解决401的问题,但却造成了大量的冗余请求。而实际上若要保证cookie有效期,只要保证适时的与后台进行交互即可。Rxjs的节流throttleTime
可以很好的满足当前的要求。
套用官方文档的一张图来简单说下:throttleTime
如图:在throttleTime
操作符下,设置了间隔为50ms。上图中axybxcx分别在第0,10,20,60,100,100ms时发射了数据。
- a 第一个发射的数据,不过滤,发送给订阅者。
- x 10ms发射的数据,距离(上一次成功发射)a间隔小于50ms,过滤,不发送给订阅者。
- y 20ms发射的数据,与a间隔小于50ms,过滤,不发送给订阅者。
- b 60ms发射的数据,与a间隔不于小50ms,不过滤,发送给订阅者。
- x 100ms发射的数据,与(上一次成功发射)b间隔小于50ms,过滤,不发送给订阅者。
- c 110ms发射的数据,与b间隔不小于50ms,不过滤,发送给订阅者。
依此理论,一个心跳的服务大概是这个样子:
import { Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
import { UserService } from './user.service';
/**
* 心跳服务
*/
@Injectable({
providedIn: 'root'
})
export class HeartbeatService {
private interval = 15 * 60 * 1000; // 时间间隔
private heartbeatSubject = new ReplaySubject<boolean>(1);
constructor(private userService: UserService) {
this.onInit();
}
/**
* 初始化心跳功能
* https://cn.rx.js.org/class/es6/Observable.js~Observable.html#instance-method-auditTime
* https://cn.rx.js.org/class/es6/Observable.js~Observable.html#instance-method-throttleTime
*/
onInit() {
this.heartbeatSubject.asObservable().pipe(throttleTime(this.interval))
.subscribe(() => {
this.userService.sendHeartbeat();
});
}
send(): void {
this.heartbeatSubject.next();
}
}
其它预发送心跳的组件直接调用send()方法即发成了心跳的发射。
auditTime
与throttleTime
相似,推荐同步学习。
防抖 debounceTime
情景二:如果10分钟内没有监听到用户的操作,则弹出锁屏界面。这功能使用防抖功能能够轻松的完成。
防抖功能的典型应用是实时查询,比如用户想搜索“河北工业大学”,实际的输入过程是这样:
“河” -- 请求1次后台(无用功)
“河北” -- 请求1次后台(无用功)
“河北工” -- 请求1次后台(无用功)
“...” -- 请求1次后台(无用功)
“河北工业大学” -- 请求1次后台(用户想要的)
如果不加入防抖,那么用户每输入一个字符都会请求一次后台,则用户输入完“河北工业大学”后,则需要请求6次后台。而用户最终仅想查询一次“河北工业大学”。假设用户的输入速度是1秒钟一个字符,则可以加入1秒的防抖 ---- 如果用户在1秒内又重新输入了新的字符,则忽略用户前面输入的;如果距离用户的最后输入时间大于1秒钟,则按用户最后的输入发起请求。这样便有效的规避了冗余请求的问题。
再借用官方文档的图片:
如图示:abcd的发射时间分别为:0,30,40,65ms。debounceTime定义了防抖时间为20ms,那么:
- a 第0ms发射,并在且20ms内没有新的要发射的内容,将数据发送给订阅者。
- b 第30ms发射,但在20ms(确切的说是在间隔10ms时)内出现了新的发射内容c,将取消发送数据。
- c 第40ms发射,在20ms内没有新的要发射的内容,将数据发送给订阅者。
- d 第65ms发射,在20ms内没有新的要发射的内容,将数据发送给订阅者。
具体到锁屏功能,大体上长这个样子:
this.xxxxSubject.asObservable().pipe(debounceTime(10 * 60 * 1000))
.subscribe(() => {
if (用户已登录) {
锁屏
}
});
send(): void {
this.xxxSubject.next();
}
总结
Rxjs的操作符有很多,当前阶段只有想不到,没有人家做不到(如果它还就真的没做到,那么我们还可以自定义操作符。同时还有机会为Rxjs提交pull request而成为Rxjs的代码贡献者)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。