面试官:请手写一个发布-订阅模式

前言

发布-订阅模式也是经典的设计模式之一,它在前端很多地方都有应用,比如javascript事件池Vue的$on、$offnodejs的events模块和socket通信等等都有应用,也是前端面试比较火热的考点之一,接下来给大家详细介绍下发布-订阅模式

发布-订阅模式定义

发布-订阅模式定义了对象间的一种一对多的依赖关系当一个对象的状态发生变化时,所有依赖它的对象都将得到通知。在JavaScript开发中,我们一般用事件模型来替代传统的发布-订阅模式。

发布-订阅模式实现

要手写一个简单的发布订阅模式,其实现思路如下:

  1. 先初始化一个events对象
  2. 调用on方法时,将事件名称eventName和监听函数fn存入events对象
  3. 调用emit方法时,通过事件名称eventNameevents对象中取出对应的回调并执行
  4. off方法:通过事件名称eventName找出events对象对应的监听函数并清除
  5. once方法:被emit触发一次后就立即调用off方法移除监听,也就是调用once传入的监听函数只会执行一次

代码不多,所以直接上完整代码。

js 复制代码
class EventEmitter {
    constructor() {
        this.events = {}
    }
    on(eventName, fn) {
        if (!this.events[eventName]) {
            this.events[eventName] = []
        }
        this.events[eventName].push(fn)
        return this
    }
    once(eventName, fn) {
        const func = (...args) => {
            this.off(eventName, func)
            fn.apply(this, args)
        }
        this.on(eventName, func)
        return this
    }
    emit(eventName, ...args) {
        if (!this.events[eventName]) return this
        this.events[eventName].forEach(fn => {
            fn.apply(this, args)
        });
        return this
    }
    off(eventName, fn) {
        if (!this.events[eventName]) return this
        if (typeof fn === 'function') {
            this.events[eventName] = this.events[eventName].filter((f) => f !== fn)
            return this
        }
        this.events[eventName] = null
        return this
    }
}

简单测试一下:

js 复制代码
const events = new EventEmitter();

events.on('event1', () => {
    console.log('event1', '第一个监听函数')
})
events.on('event1', () => {
    console.log('event1', '第二个监听函数')
})
events.emit('event1')

const fn1 = () => {
    console.log('event2', '第一个监听函数')
}
const fn2 = () => {
    console.log('event2', '第二个监听函数')
}
events.on('event2', fn1)
events.on('event2', fn2)
events.off('event2', fn1);

// 打印结果:
// event1 第一个监听函数
// event1 第二个监听函数

ok,大功告成了!

发布-订阅模式的作用

  • 可以广泛应用于异步编程中,这是一种替代传递回调函数的方案;
  • 可以取代对象之间硬编码的通知机制,一个对象不用再显示地调用一个对象的接口。

发布-订阅模式的优缺点

优点:

  • 解耦性:解耦了发布者和订阅者,让彼此独立,更加容易维护和扩展;
  • 异步通信:发布者和订阅者不受时间限制,可以在任意时间发布和订阅事件。

缺点:

  • 难以调试和追踪 :如果过度使用的话,系统中存在大量发布者和订阅者,会导致程序难以跟踪维护和理解。比如实际vue项目中大量运用了事件总线$bus的通信,会增加追踪和调试程序的难度
  • 增加系统复杂性:引入发布订阅模式到系统中进行消息通信,无疑会增加系统复杂度。

小结

发布-订阅模式在各个框架源码中有非常多的应用,我们了解其内部原理和实现思路之后,其实也能帮助我们更好地去理解和使用它,同时这个也是前端面试的必备知识点之一,掌握好它准没错!

相关推荐
柯南二号14 分钟前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy729316 分钟前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲28 分钟前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6
究极无敌暴龙战神X31 分钟前
前端学习之ES6+
开发语言·javascript·ecmascript
王解33 分钟前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
欲游山河十万里34 分钟前
(02)ES6教程——Map、Set、Reflect、Proxy、字符串、数值、对象、数组、函数
前端·ecmascript·es6
明辉光焱34 分钟前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
PyAIGCMaster1 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python
baozhengw1 小时前
UniAPP快速入门教程(一)
前端·uni-app
nameofworld1 小时前
前端面试笔试(二)
前端·javascript·面试·学习方法·数组去重