su37josephxia / frontend-interview

前端面试知识点
MIT License
159 stars 45 forks source link

解释一下事件与订阅发布的关系 #117

Open su37josephxia opened 2 years ago

zcma11 commented 2 years ago

两者实现方式是相似的,都是通过收集回调,然后时机到了遍历调用实现。发布订阅是关注和被关注者双方的互动,而事件是有一个控制中心,管理着多个事件,并且只要愿意,是可以串台的,当然也很少这样干。事件的话就比如浏览器的 addEventListener。

QbjGKNick commented 2 years ago

发布订阅模式是一种对象间一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都将得到状态改变的通知。订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到调度中心时也就是触发事件时,就会由调度中心统一调度订阅者注册到调度中心的处理代码。 要实现该模式需要两个步骤:

对于事件的监听模式而言,它这里面涉及到三个重要概念:事件+事件监听器+事件源。

674252256 commented 2 years ago
superjunjin commented 2 years ago
wzl624 commented 2 years ago
RJM1996 commented 2 years ago

事件和发布订阅的关系

什么是事件?

const btn = document.getElementById("btn");
btn.addEventListener("click", function (e) {
  console.log(e)
}, false);

addEventListener 中的第一个参数 click 就是一个事件,第二个参数就是事件处理程序

上述代码包含几个关键对象:

  1. btn 节点(事件源)
  2. click 事件(事件)
  3. 事件处理函数(事件驱动程序)

addEventListener() 的工作原理是将实现 EventListener 的函数或对象添加到调用它的 [EventTarget](https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget) 上的指定事件类型的事件侦听器列表中。也就是说在 btn 这个对象中针对每一种事件类型,都有一个事件侦听器列表,上述代码就是将事件处理函数添加到 btn 对象中 click 类型事件的侦听器列表中。

事件和发布订阅的关系

在发布订阅模式中有三个角色:

  1. 发布者 Publisher
  2. 事件调度中心 Event Channel
  3. 订阅者 Subscriber

将这三个角色套用到上面 dom 事件的处理逻辑中:

  1. 对 btn 对象的 click 事件添加一个事件处理函数 ,就相当于订阅操作
  2. 触发 click 事件就相当于发布的操作

我理解这里的事件调度中心就是 btn 对象,在 btn 对象中维护着各种事件的侦听器列表;

事件处理函数就相当于订阅者,订阅了这个事件,当事件触发时会通知事件处理函数进行执行;

发布者就是触发事件的对象,可能是用户点击,或者直接执行 btn.onclick()

并且发布订阅是一种一对多的关系,例如我们可以针对 click 事件注册多个事件处理函数,这些函数都会添加到 click 事件的侦听器列表中,当事件触发时依次执行。

总结

事件就是发布订阅模式的一种具体实现,本质就是一种消息通知机制,使得订阅者和发布者能够通过一个第三方渠道进行通信。

JanusJiang1 commented 2 years ago

事件: 事件是观察者模式,在对象之间定义一个一对多的依赖,当对象自身状态改变的时候,会自动通知给关心该状态的观察者。这种对象与对象,有点像 商家-顾客 的关系。 案例: document.addEventListener('click',()=>{})

订阅发布:

该模式理解起来和观察者模式一样,也是定义一对多的依赖关系,对象状态改变后,通知给所有关心这个状态的订阅者。 订阅发布模式有订阅的动作,可以不和商家直接产生联系,只要能订阅上关心的状态即可,通常利用第三方媒介来做,而发布者也会利用三方媒介来通知订阅者。 这有点像 商家-APP-顾客 的关系。 在程序实现中,第三方媒介称之为 EventBus(事件总线),可以理解为订阅事件的集合,

// 订阅
EventBus.on('custom', () => {})
// 发布
EventBus.emit('custom')

案例:

异同:

从概念上理解,两者没什么不同,都在解决对象之间解耦,通过事件的方式在某个时间点进行触发,监听这个事件的订阅者可以进行相应的操作。

在实现上有所不同,观察者模式对订阅事件的订阅者通过发布者自身来维护,后续的一些列操作都要通过发布者完成;订阅发布模式是订阅者和发布者中间会有一个事件总线,操作都要经过事件总线完成。

jj56313751 commented 2 years ago

发布订阅模式有一个事件通道作为调度中心,管理事件的订阅与发布工作,隔绝了订阅者与发布者的依赖关系。订阅者在订阅事件时,只关注事件本身,不关心谁发布这个事件;发布者在发布事件时,只关注事件本身,不关心谁订阅了这个事件

jiafei-cat commented 2 years ago

浏览器的事件系统本质就是发布订阅模式的一种实现 事件的订阅发布流程:

从上面说的流程来看,浏览器的事件系统与发布订阅是一致的

ruixue0702 commented 2 years ago

事件与订阅发布的关系?

在发布订阅模式中,发布者和订阅者不知道彼此的存在,发布者不能够直接将消息发送给订阅者 可以通过调度中心来维持订阅者和发布者之间的联系; 调度中心也可称为事件总线; 订阅者将订阅的事件注册到调度中心; 发布者发布事件到调度中心; 调度中心统一处理发布者发布的信息并发送给相应的订阅者

rachern commented 2 years ago

发布订阅模式

发布订阅模式由三部分组成

在 DOM 中的事件的实现本质上就是发布订阅模式:

crazyyoung1020 commented 2 years ago

发布订阅模式中,发布者-事件中心-订阅者,三者的关系是独立的,互不耦合。 订阅者去事件中心订阅自己感兴趣的事情并注册自己的回调,发布者去事件中心通知事件中心发布相关事件,事件发布后,所有的订阅了该事件的订阅者在事件中心注册的回调都会执行。

发布订阅模式在前端应用非常广泛,比如

  1. webpack的tapable钩子订阅就是利用了发布订阅模式,插件去compiler的hooks里订阅相关钩子,并注册自己的回调,当事件执行的时候,所有订阅了该钩子的插件的回调都会执行。

  2. babel在traverse遍历ast的时候,也是利用了发布订阅模式,babel插件去订阅ast的相关节点,当遍历到这个节点的时候,会去通知所有订阅了的babel插件,并执行他们的回调。