发布订阅模式11

如何实现?

  1. 想好谁是发布者
  2. 给发布者一个缓存列表 用于存放回调函数来通知订阅者
  3. 发布消息 发布者遍历这个缓存列表 依次触发里面存放的订阅者回调函数
    //先订阅
    var shopObj = {};  //定义发布者
    shopObj.list = []; //缓存列表 存放的是订阅的函数

    //增加订阅者

    shopObj.listen = function (fn) { //回调函数fn
        shopObj.list.push(fn)
    };

    //发布消息
    shopObj.trigger = function () {
        for (var i = 0, fn; fn === this.list[i++];){ //???
            fn.apply(this, arguments)
        }
    };

    //监听
    shopObj.listen(function (color, size) {
        console.log('颜色是${color}');
        console.log('尺码是${size}')
    });
    shopObj.listen(function (color, size) {
        console.log('再次颜色是${color}');
        console.log('再次尺码是${size}')
    });
    //触发,
    //小红
    shopObj.trigger('red',42);
    //小明
    shopObj.trigger('black',43)

在这里插入图片描述
打印结果可以看出:把消息发布给了所有人

    //先订阅
    var shopObj = {};  //定义发布者
    shopObj.list = []; //缓存列表 存放的是订阅的函数

    //增加订阅者
    shopObj.listen = function (key, fn) { //回调函数fn
        if(!this.list[key]){
            this.list[key] = []
        }
        shopObj.list[key].push(fn)
    };

    //发布消息
    shopObj.trigger = function () {
        //对应的key取出来
        var key = Array.prototype.shift.call(arguments) //argument不具备shift方法
        var fns = this.list[key]
        if (!fns || fns.length === 0){
            return
        }
        for (var i = 0, fn; fn === this.list[i++];){ //???
            //fn.apply(this, arguments) //用es6怎么替代?arguments是数组
            fn(...arguments)
        }
    };
    //给一个唯一key值
    shopObj.listen('red',function (size) {
        console.log('尺码是${size}')
    });
    shopObj.listen('black',function (size) {
        console.log('尺码是${size}')
    });
    //小红
    shopObj.trigger('red',42);
    //小明
    shopObj.trigger('black',43)

打印结果:
在这里插入图片描述

简单封装

    var event = {
        list:[],
        listen: function (key, fn) { //回调函数fn
            if(!this.list[key]){
                this.list[key] = []
            }
            shopObj.list[key].push(fn)
        },
        trigger: function () {
            //对应的key取出来
            var key = Array.prototype.shift.call(arguments) //argument不具备shift方法
            var fns = this.list[key]
            if (!fns || fns.length === 0){
                return
            }
            for (var i = 0, fn; fn === this.list[i++];){ //???
                //fn.apply(this, arguments) //用es6怎么替代?arguments是数组
                fn(...arguments)
            }
        }
    }
    //取消订阅
    event.remove = function (key, fn) {
        var fns = this.list[key]
        if (!fns) {
            return false
        }
        if(!fn){
            fn && (fns.length = 0)
        }else {
            for (var i = fns.length - 1; i >= 0; i--){
                var _fn = fns[i]
                if (_fn === fn) {
                    fns.splice(i, 1)
                }
            }
        }
    }

完整的

    var Event = (function () {
        var list = {},
        listen,
        trigger,
        remove;
        listen = function (key, fn) { //回调函数fn
            if(!this.list[key]){
                this.list[key] = []
            }
            shopObj.list[key].push(fn)
        }
        trigger = function () {
            //对应的key取出来
            var key = Array.prototype.shift.call(arguments) //argument不具备shift方法
            var fns = this.list[key]
            if (!fns || fns.length === 0){
                return
            }
            for (var i = 0, fn; fn === this.list[i++];){ //???
                //fn.apply(this, arguments) //用es6怎么替代?arguments是数组
                fn(...arguments)
            }
        }
        remove = function (key, fn) {
            var fns = this.list[key]
            if (!fns) {
                return false
            }
            if(!fn){
                fn && (fns.length = 0)
            }else {
                for (var i = fns.length - 1; i >= 0; i--){
                    var _fn = fns[i]
                    if (_fn === fn) {
                        fns.splice(i, 1)
                    }
                }
            }
        }
        return {
            listen,
            trigger,
            remove
        }
    })()

改进异步操作中的强耦合

业务场景

加入正在开发一个商城网站,网站里有header头部、nav导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件,就是必须先用ajax异步请求获取用户的登录信息。
这是很正常的,比如用户的名字和头像要显示在header模块里,而这两个字段都来自用户登陆后返回的信息
//伪代码
login.succ(function(data){
	header.setAvatar(data.avatar); //设置header 模块的头像
	nav.setAvatar(data.avatar);//设置导航模块的头像
	message.refresh(); //刷新消息列表
	cart.refresh();//刷新购物车列表
});

这种缺点:耦合度太高

发布订阅模式 实现低耦合

用发布-订阅模式重写之后,对用户信息感兴趣的业务模块将自行订阅登录成功的消息事件。当登录成功时,登录模块只需要发布登录成功的小小,而业务方接受到消息之后,就会开始进行各自的业务处理,登录模块并不关心业务方究竟要做什么,也不想了解他们的内部细节
$.ajax('http://xx.com?login', function (data) {//登录成功
        login.trigger('loginSucc',data); //发布登录成功的消息
    })
    //各模块鉴定登录成功的消息
    var header = (function () { //header模块
        login.listen('loginSucc',function (data) {
            header.setAvatar(data.avatar);
        });
        return{
            setAvatar: function (data) {
                console.log('设置header 模块的头像');
            }
        }
    })();

    var nav = (function () { //nav模块
        login.listen('loginSucc',function (data) {
            nav.setAvatar(data.avatar);
        });
        return{
            setAvatar:function (avatar) {
                console.log('设置nav 模块的头像');
            }
        }
    })();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值