观察者模式也叫发布订阅模式. 最经典的用法就是在事件监听里面.
<button onClick = "handle()"> 确认 </button>
handle 方法订阅了 onClick 事件, 当用户点击 (发布)onClick, handle 方法触发
大致提一下, 网上对观察者模式的解释有很多. Observable 就是基于观察者模式实现的
Observable 方法的定义
基本特征:
是一个函数
接受一个 Observer 对象
返回一个具有 unsubscribe 功能的函数或者对象
- let ob = new Observable(obser => {
- // 这个函数是 "发布"
- obser.next()
- })
- // 订阅了 console.log(12) 动作
- ob.subscribe({
- next(){console.log(12)}
- })
注: 只有 subscribe 方法执行了才会执行 "发布" 函数
在 core-JS 中已对 observable 做了扩展, 通过 import "core-js/es7/observable" 可以使用 Observable
实现 Observable 方法
便于理解, 还是简单的实现一个 Observable 吧, 代码如下
- class SubscriptionObserver {
- constructor(ob, debounceTime){
- this.ob = ob || {};
- this.debounceTime = debounceTime;
- this.unSub = false;
- this.timeout = null;
- }
- next(value){
- if (!this.unSub && this.ob.next){
- clearTimeout(this.timeout)
- this.timeout = setTimeout(() => {
- !this.unSub &&this.ob.next(value);
- this.timeout = null;
- }, this.debounceTime)
- } else {
- this.ob.next(value);
- }
- }
- error(){
- if (!this.unSub && this.ob.error){
- this.ob.error();
- }
- }
- complete(){
- if (!this.unSub && this.complete){
- this.ob.complete();
- }
- }
- unsubcribe(){
- this.unSub = true;
- }
- }
- class Observable {
- constructor(SubscriptionOb) {
- this.SubscriptionOb = SubscriptionOb;
- }
- subscribe(ob){
- this.subOb = new SubscriptionObserver(ob, this.timeout);
- return this.SubscriptionOb(this.subOb);
- }
- unsubcribe(){
- this.subOb.unsubcribe()
- return this;
- }
- debounceTime(timeout){
- this.timeout = timeout;
- return this;
- }
- }
主要增加了 debounceTime 功能, 在 debounceTime 在 lazy 时间内只会执行最后一次 next 方法
搜索框的应用
搜索框的搜索主要是要解决 2 个问题
不能在用户输入每个字符的时候就触发搜索.
服务器的异步返回时间不一致, 先搜索的字符可能数据可能返回比后搜索的慢
代码如下
- export default class Tudos extends React.Component {
- state = {
- text:""
- }
- // 搜索关键字接口
- searchKeyWords(text){
- return new Promise((resolve) => {
- setTimeout(() => {
- let list = [{...}...]
- resolve(list)
- }, 2000)
- })
- }
- handleInput(dom) {
- let oba = new Observable(ob => {
- dom.oninput = e => {
- ob.next(e.target.value)
- }
- }).debounceTime(500).subscribe({
- next(value){getList(value)}
- })
- }
- render() {
- return (<div>
- <input ref = {dom => dom && this.handleInput(dom)}/>
- </div>)
- }
- }
总会在用户输入完 500 毫秒后执行 next 函数. 这个上述代码已实现. 第二个问题还未解决!
引入 RxJS
安装
NPM i @reactivex/rxjs --save;
引入
import * as Rx from "@reactivex/rxjs";
RxJS 当做是用来处理事件的 Lodash . 像这种复杂的事件处理第一个就是想到使用 RxJS
具体的使用可以参考以下官方文档 https://cn.rx.js.org/manual/overview.html
代码如下
- export default class SimpleSortableList extends Component {
- componentDidMount() {
- }
- // 搜索关键字接口
- searchKeyWords(text){
- return new Promise((resolve) => {
- setTimeout(() => {
- let list = [{...}...]
- resolve(list)
- }, 2000)
- })
- }
- handleInput(button){
- Rx.Observable.fromEvent(button, 'input')
- .debounceTime(500)
- .switchMap(e => {
- return Rx.Observable.create(ob => {
- this.searchKeyWords(e.target.value).then(res => {
- ob.next(list)
- })
- });
- })
- .subscribe(text => console.log(text))
- }
- render() {
- return (
- <div className={prefix}>
- <input ref = { dom => dom && this.handleInput(dom)} />
- </div>
- );
- }
- }
通过 debounceTime 延迟返回结果
通过 switchMap 丢弃上一个未及时返回的结果
而且整个代码显得如此短小精悍
来源: https://juejin.im/post/5bc84b375188255c554728f1