zoukankan      html  css  js  c++  java
  • 前端基础走查(五):事件和通信以及发布订阅模式

    什么是事件?

    事件是您在编程时系统内发生的动作或者发生的事情,系统响应事件后,如果需要,您可以某种方式对事件做出回应。浏览器和Node的事件有所不同

    1. 使用方式不同。浏览器中使用dispatchEvent 来发布事件,使用addEventListener来绑定并监听事件。Node中使用emit触发事件,使用on来监听事件。
    2. 作用对象不同。浏览器中主要为DOM事件,回掉函数中存在事件对象(event),可以理解为对外开放的钩子。Node依赖定期监听事件的监听器和定期处理事件的处理器。

    事件与消息队列

    事件的产生:Node.js 所有的异步 I/O 操作(net.Server, fs.readStream 等)在完成后都会添加一个事件到事件循环的事件队列中

    事件的触发:事件循环会在事件队列中取出事件处理,从事件循环取出事件的时候,触发这个事件和回调函数。

    消息队列:js任务都是排队执行的,每当一个任务执行之前都插入到消息队列最后,当前面没有任务时才进入主线程执行。

    事件机制

    浏览器中的DOM事件有事件流(事件捕获、事件冒泡),出现事件流的原因是DOM的树形结构,由于这种嵌套的结构会形成一种包含关系,事件的触发会波及其父子元素。浏览器也提供了阻止冒泡(event.stopPropagation())和阻止默认(event.preventDefault())的方法。由此也衍生出了事件委托的优化手段,事件统一处理。我们常见的DOM事件有鼠标的点击、悬浮、滑动等等,当然浏览器也提供给开发者自定义事件的能力,使用示例如下:

      window.addEventListener('hello',(e)=>{
        console.log(e.detail)
      });
      window.dispatchEvent(new CustomEvent('hello', {detail:{name:'张三'}}));
    

    Node主要是做服务端应用的框架,也提供了事件机制。其主要包含触发器和监听器,主要是EventEmitter类,基本上就是自定义事件,实现原理也就是一个发布-订阅模式。使用示例如下:

      const EventEmitter = require('events');
      const myEmitter = new EventEmitter();
    
      myEmitter.on('hello', (res) => {
        console.log(res);
      });
      
      myEmitter.emit('hello', {name:'张三'});
    

    js通信方式汇总

    • postMessage与iframe
    • 客户端与服务器通信(http、websocket)
    • h5与native通信
      JsBridge
    • node.js进程之间通信
      process.send()
    • vue和react组件间的通信方式

    观察者模式与发布-订阅模式

    观察者模式:观察者和被观察这之间存在耦合关系,观察这直接观察被观察者,两者必须确切知道对方存在才能进行消息传递
    发布-订阅模式:观察者和被观察者通过一个消息中心来代理,促成两者之间进行通信。发布者和订阅者完成的解耦,两者不需要知道对方是否存在。

    观察者模式相当于我们直接去超市买东西,实时交易。
    发布-订阅模式相当于我们网上买东西,我们先下单,货到了物流会给你发短信。

    分别手写一个观察者和发布-订阅模式

    观察者模式

    /**
     * 观察者模式
     */
    
    /**
     * 观察者
     */
    function Observer(id) {
      this.id = id;
      this.update = (obs) => {
        console.log('观察者:'+this.id);
        console.log('被观察者:'+obs.id);
      }
    }
    /**
     * 被观察者
     */
    function Observed() {
      this.observers = [];
      this.addObserver = (obs) => {
        this.observers.push(obs);
      }
      this.removeObserver = (obs) => {
        this.observers = this.observers.filter(item=>item.id!==obs.id);
      }
      this.notify = (obs) => {
        this.observers.forEach(item=>item.update(obs));
      }
    }
    
    // 测试
    const observed = new Observed();
    
    const observer1 = new Observer(1);
    const observer2 = new Observer(2);
    const observer3 = new Observer(3);
    
    observed.addObserver(observer1);
    observed.addObserver(observer2);
    observed.addObserver(observer3);
    
    observed.notify(observer1);
    
    

    发布-订阅模式

    const createEventHub = () => ({
      hub: Object.create(null),
      // 订阅
      sub(event,handle){
        if(!this.hub[event]) this.hub[event]=[];
        this.hub[event].push(handle);
      },
      //发布
      pub(event,data){
        (this.hub[event] || []).forEach(handle=>handle(data));
      },
      //取消
      off(event,handle){
        let index = this.hub[event].indexOf(handle);
        index>-1 && this.hub[event].splice(index,1);
      }
    })
    
    // 测试
    const eventHub = createEventHub();
    const handle = data =>{
      console.log(data);
    }
    
    eventHub.sub('myEvent',handle);
    eventHub.sub('myEvent',()=>{
      console.log('handle2')
    });
    eventHub.sub('myEvent2',()=>{
      console.log('eventHub',eventHub);
    });
    
    eventHub.pub('myEvent','a string !!!');
    eventHub.pub('myEvent',{arg:'a object!!!'});
    eventHub.pub('myEvent2');
    
    eventHub.off('myEvent',handle);
    

    问题汇总(FAQ)

    • 浏览器跨域问题的解决方案
    • h5与native如何通信
    • node.js进程通信
    • 浏览器事件委托
    • Node Events on方法(监听函数)的调用是同步的还是异步的

    参考

  • 相关阅读:
    MySQL中默认值中用时间函数的问题
    mysql数据表的操作
    mysql数据库的基本操作
    mysql数据库的几个基本概念
    【转载】CentOS6.5_X64下安装配置MongoDB数据库
    Swap Swap,即交换分区
    linux中给PHP安装mongodb的扩展
    centos yum 安装 mongodb 以及php扩展
    设计模式主要分三个类型:创建型、结构型和行为型
    MySQL DELETE语句和TRUNCATE TABLE语句的区别
  • 原文地址:https://www.cnblogs.com/xingguozhiming/p/14200073.html
Copyright © 2011-2022 走看看