美文网首页饥人谷技术博客
JavaScript模块间交流的两种方式:命名空间和发布订阅模式

JavaScript模块间交流的两种方式:命名空间和发布订阅模式

作者: 张路1806 | 来源:发表于2018-12-26 03:51 被阅读1次

本文只涉及两种模式的简单使用,基本概念的阐述,发布订阅模式的更深层解耦问题并没有涉及。

模块之间的交流

模块之间并非独立,通常是相互协作的方式工作,因为都使用局部变量,所以需要一种机制来相互沟通。这里简单介绍两种方式:

  1. 命名空间
  2. 发布订阅模式

命名空间

优点:可以防止全局变量污染代码。
因为在模块之间,我们需要在多个模块互相调用数据,这个时候当然可以直接使用全局变量window,但是这样使用就会产生非常多的全局变量。有一种解决方式就是命名空间(并非最好方式),代码如下:

//html中调用app.js//
<script src:./app.js></script>
//app.js的内容//
window.app = window.app || {}
//如果window.app存在,那么不改变,如果不存在,就初始化为空对象。//
//在其他的模块中(模块应该使用类或者IIFE等方式使用局部变量)// 
window.app.any = 局部变量

这个时候当我们想在其他的模块使用这个局部变量的函数的时候,就能使用window.app.any.fn()调用,而不会污染全局变量

缺点:这样的两个模块或者更多的模块是耦合的,彼此之间相互依赖,没有办法分开。实际代码中的弊端就是改动一个模块,就会出现连锁反应。
另外一种方式就是发布订阅模式。

发布订阅模式

这是模块之间传输数据的一种比较好的方式,他可以让所有的模块数据集中处理,就好像工厂中做汽车,各个车的部分分开制造,需要方向盘的时候就把需求上报,然后中枢发出指令制造方向盘,而方向盘制造的人不知道是谁需要,只要制作就可以了。

用途:模块之间传值
优点:模块之间解耦,保持相对的独立性

在一个中枢模块中,声明eventHub

window.eventHub = {
    events:{
        key: [],
    }
    init(){},
    on(eventName,fn){},
    emit(eventName,data){},
    off(){},
}

这里主要介绍

  1. 发布window.eventHub.emit(eventName,data)
  2. 订阅window.eventHub.on(eventName,fn)
    虽然叫做发布-订阅模式,但是在先后顺序上是先订阅再发布,就像报纸一样,先在电话中订阅,送报员才会把报纸送过来。
  • 订阅的作用:查询什么事件(eventName),这个事件需要执行什么函数(fn),将函数添加进事件的数组中;
  • 发布的作用:执行什么事件(eventName),把这个事件中的每一个函数都执行一遍,函数需要的data就按需要给;

订阅的实现方式(上文代码补全):

...
on(eventName,fn){
     if(window.eventHub.events[eventName] === undefined){
            window.eventHub.events[eventName] = []
     }
     window.eventHub.events[eventName].push(fn)
}

也可以写成

...
on(eventName,fn){
     if(this.events[eventName] === undefined){
            this.events[eventName] = []
     }
     this.events[eventName].push(fn)
}

这样就完成了事件还没有生成的初始化,并且将fn加入执行清单当中了


发布的实现方式(上文的代码补全):

...
emit(eventName,data){
    for(let key in window.eventHub.events){
        if(key === eventName){
            window.eventHub.events[key].map((fn)=>{
                return fn(data)
            })
        }
    }
}

也可以写成

...
emit(eventName,data){
    for(let key in this.events){
        if(key === eventName){
            this.events[key].map((fn)=>{
                return fn(data)
            })
        }
    }
}

这样就遍历所有的事件名称,然后找到匹配的eventName,然后执行数组中所有的函数。


那么需要在其他模块中订阅时,

...
window.eventHub.on('download',fn(data){
    console.log('我订阅了download事件,当download事件发布时,我就会被打印,fn就会被执行')
})
...

在模块中发布:

...
window.eventHub.emit('download',data)
...

此文记录学习过程中的心得笔记,如有错误欢迎指出

相关文章

网友评论

    本文标题:JavaScript模块间交流的两种方式:命名空间和发布订阅模式

    本文链接:https://www.haomeiwen.com/subject/jydclqtx.html