zoukankan      html  css  js  c++  java
  • 发布订阅模式与简单实现

    发布订阅模式与简单实现

    本文写于 2020 年 9 月 22 日

    观察者模式(Observer Pattern)是一种设计模式,也可以叫做「发布-订阅模式」。

    等等,其实我也不清楚,通常你在网上会看到上面这一段话,但我在 Angular 文档中读到谷歌的说法是这样的:观察者模式和发布/订阅模式非常相似(但不完全一样)。

    好吧,我们姑且就直说发布订阅模式吧。

    发布订阅模式就像你订了一本杂志,每当杂志新刊发布的时候,所有订阅过杂志的人都会收到新刊一样。

    观察者模式定义了对象之间一种 一对多 的依赖关系,每当该对象的状态发生改变的时候,所依赖于它的其他对象都将得到通知。

    在 JavaScript 中,我们会经常接触到一个很类似的东西——事件。

    事件与观察者模式

    我们先为一个 #app 元素添加两个点击事件:

    document.querySelector('#app').addEventListener('click', () => {
      // 事件 1
    });
    document.querySelector('#app').addEventListener('click', () => {
      // 事件 2
    });
    

    这个时候,我们点击 #app 元素或者使用 document.querySelector('#app').click() 或者 document.querySelector('#app').dispatchEvent('click') 来触发时,这两个事件都会被触发——是不是类似与很多对象依赖于一个对象,该对象改变后所有依赖者都会被触发。

    自定义「发布-订阅」

    我们来自定义一个事件来试试。

    首先我们需要一个数组储存所有的触发函数,这样我们就可以对其进行遍历,后触发每一个事件。

    const children = [];

    我们还需要一个方法,来对 children 数组进行 push

    const listen = (fn) => {
      children.push(fn);
    }
    

    我们再增加一个触发函数 trigger,让它去遍历并触发我们的 children

    const trigger = () => {
      children.forEach((child) => {
        child();
      })
    }
    

    OK,接下来我们整合一下:

    class eventHub {
      children = {}
    
      listen(key, fn) {
        if(this.children[key]) {
          this.children[key].push(fn);
        } else {
          this.children[key] = [fn]
        }
      }
    
      trigger(key) {
        this.children[key]?.forEach((child) => {
          child();
        });
      }
    
      remove(key, fn) {
        if(this.children[key]) {
          const children =this.children[key]
          const target = children.indexOf(fn)
          this.children[key] = [...children.slice(0, target), ...children.slice(target + 1)]
        }
      }
    }
    

    这里我们将数组换成了对象,并且为函数增加了参数,因为我们希望够可以对多个事件进行监听。

    还添加了一个移除事件——所以我们最好使用具名函数,如果是匿名函数就无法移除监听了!

    有哪些例子?

    例如一个电商网站的登陆系统,需要获取用户基础信息后,获取用户的各项历史记录:

    function onLogin() {
      getUserInfo()
        .then(() => {
          return getUserHistory()
        })
        .then(() => {
          getUserXXX()
        })
    }
    

    那么一旦我们需要新增一个功能,就需要在这个长函数中增加新项。

    如果使用了发布-订阅模式,就可以非常简单的写上新的、独立的事件监听了。

    (完)

  • 相关阅读:
    iview数字输入框InputNumber值改变后value的获取
    一个元素完全覆盖在另一个元素之上
    点击某链接跳转到另一页面并在页面执行某链接传参的点击方法
    前后端分离实现django日志下载,celery日志下载
    datetime 使用
    jquery replace(" "," ")替换问题-全部替换
    jquery 将数组(列表)格式的字符串转换成数组,将字典格式的字符串转换成数组
    Navicat for Mysql查询结果导出无表名
    python 实现文件夹下所有文件或文件夹重命名
    python 虚拟环境相关命令
  • 原文地址:https://www.cnblogs.com/xhyccc/p/13710065.html
Copyright © 2011-2022 走看看