发布-订阅模式简述

325 阅读1分钟

1.简述:

发布-订阅也叫观察者模式,在javascript中常应用为事件监听。

2.实现发布订阅模式的步骤

1.确定充当发布者的对象 2.然后给发布者添加一个缓存列表,里面放入回调函数 3.当事件发生时,遍历并触发订阅这个事件的缓存列表

案例:书店为了减少库存,只有在消费者付了订金订某本书后,才会去批发商那里进货,进货后会通知订书的买家来拿


    let BookProvider = {}
    BookProvider .clientList = {}
    BookProvider .listener = function(key, fn){
    	if (!this.clientList[key]){
    		this.clientList[key] = []
    	}
    	this.clientList[key].push(fn)
    }
    BookProvider .trigger = function(){
    	let args = [].slice.apply(arguments)
    	let key = args.shift()
    	let that = this
    	
    	if (!this.clientList[key] || !this.clientList[key].length){
    		return false
    	}
    	this.clientList[key].forEach(function(fn){
    		fn.apply(that, args)
    	})
    }

    //调用
    BookProvider .listener('javascript设计模式', function(msg){console.log('小明:'+msg)})
    BookProvider .listener('javascript设计模式', function(msg){console.log('小红:'+msg)})
    BookProvider.trigger('javascript设计模式', '付钱拿书')

    //通用订阅发布模式,让普通的对象获得被订阅和发布的能力
    function initEvent(o){
        let event = {}
        function listener(key, fn){
            if (!event[key]){
                event[key]= []
            }
            event[key].push(fn)
        }
    
        function trigger(...args){
            let key = args.shift()
            let fns = event[key]
            if(!fns){
                return false
            }
        
            fns.forEach(f => {
                f.apply(this, args)
            })
        }
    
        function removeListener(key, fn){
            let fns = event[key]
            if (!fns){
                return false
            }
        
            if (!fn){
                fns.length = 0 //不传fn就把该事件下的所有监听函数删除
            }else {
                for (let i = fns.length - 1; i >= 0; i--){
                    if (fns[i]== fn){
                        fns.splice(i, 1)
                    }
                }
            }
        }
        return Object.assign(o, {
            listener,
            trigger,
            removeListener
        })
    }

3.真实案例

首页获取用户信息后初始化页面


    login.success(data){
        cart.init(data)
        header.init(data)
        msg.init(data)
        ....
    }

每当需要一个模块需要用户数据时就要在login里面改,这样针对具体实现的代码不好维护,需要用发布订阅模式改写


    //login.js一部分代码
    $.ajax(url, ()=>{
        login.trigger('success', data)
    })
    
    //cart.js
    let cart = (function(){
        login.listener('success', data => {
            cart.init(data)
        })
    
        return {
            init: function(data){
                ......
            }
        }
    })()

参考资料:《JavaScript设计模式与开发实践》