精华内容
下载资源
问答
  • 发布订阅
    千次阅读
    2022-01-13 00:29:23

    什么是发布订阅模式

    发布订阅模式是软件开发者很常见的一种设计模式,很多开源库都使用了发布订阅模式,例如RxJava、EventBus、Vue等,所以学习该模式还是很有必要的。

    该模式中存在一个或多个发布者,一个或多个订阅者,当发布者发布消息的时候,参与订阅的订阅者会收到对应的消息通知。其实核心原理就是使用一个集合来存储所有的订阅者类,当发布消息的时候遍历这个集合,并调用集合中的每一个订阅者类的通知方法。

    下面以一段代码实现发布-订阅原理。

    实现发布-订阅原理

    一、创建发布者

    1、首先定义一个接口,所有的发布者都要实现该接口,该接口定义添加订阅者、发送消息、移除订阅者方法。

    public interface IPublisher {
    
        /**
         * 添加订阅者
         */
        void emit(ISubscriber subscriber);
    
        /**
         * 触发消息
         */
        void on(String msg);
    
        /**
         * 移除订阅者
         */
        void remove(ISubscriber subscriber);
    
    }
    

    2、创建发布者

    这里以EventBus为例,实现发布者接口,并在该类中创建一个集合来添加存储订阅者。当发布消息的时候遍历该集合,调用订阅者的通知函数,将消息发送出去。

    public class EventBus implements IPublisher {
    
        // 定义一个集合来存储订阅者
        private ArrayList events = new ArrayList<Subscriber>();
    
        // 发布者名称
        private String name;
    
        // 创建发布者
        public EventBus(String name) {
            this.name = name;
        }
    
        @Override
        public void emit(ISubscriber subscriber) {
            // 将每一个新的订阅者添加到集合中维护
            events.add(subscriber);
        }
    
    
        @Override
        public void on(String msg) {
            // 触发订阅的原理就是遍历该集合,然后将消息发送给集合中的每一个订阅者
            for (int i = 0; i < events.size(); i++) {
                Subscriber subscriber = (Subscriber) events.get(i);
                subscriber.on(this.name, msg);
            }
        }
    
        @Override
        public void remove(ISubscriber subscriber) {
            // 移除订阅者
            events.remove(subscriber);
        }
    
    }
    

    二、创建订阅者

    1、定义订阅者接口,接口定义收到消息监听方法,所有的订阅者都实现该接口。

    public interface ISubscriber {
        
        void on(String publisher, String msg);
        
    }
    

    2、创建订阅者,订阅者实现ISubscriber接口。

    public class Subscriber implements ISubscriber {
    
        // 订阅者名称
        private String name;
        private Receiver receiver;
    
        public interface Receiver {
            void onMessage(String publisher, String msg);
        }
    
        // 创建订阅者
        public Subscriber(String name) {
            this.name = name;
        }
    
        // 创建订阅者,也可以加个回调函数,用来将消息回调出去
        public Subscriber(String name, Receiver receiver) {
            this.name = name;
            this.receiver = receiver;
        }
    
        @Override
        public void on(String publisher, String msg) {
            // 这里会收到发布者消息,然后做相应的处理,一般这里会创建一个回调函数,通过回调函数将消息发送出去
            System.out.println(publisher + "发布了新消息;" + this.name + ",收到消息通知:" + msg);
            if (receiver != null) {
                receiver.onMessage(publisher, msg);
            }
        }
    }
    

    三、使用示例

    Subscriber subscriber1 = new Subscriber("张三", new Subscriber.Receiver() {
        @Override
        public void onMessage(String publisher, String msg) {
            // 收到消息
            System.out.println(publisher + ":" + msg);
        }
    }); // 创建订阅者张三
    Subscriber subscriber2 = new Subscriber("李四"); // 创建订阅者李四
    Subscriber subscriber3 = new Subscriber("王五"); // 创建订阅者王五
    
    EventBus eventBus = new EventBus("小明"); // 创建发布者小明
    eventBus.emit(subscriber1); // 添加张三订阅者
    eventBus.emit(subscriber2); // 添加李四订阅者
    eventBus.emit(subscriber3); // 添加王五订阅者
    
    eventBus.on("祝你虎年大吉大利"); // 发布新消息
    

    示例结果:

    小明发布了新消息;张三,收到消息通知:祝你虎年大吉大利
    小明:祝你虎年大吉大利
    小明发布了新消息;李四,收到消息通知:祝你虎年大吉大利
    小明发布了新消息;王五,收到消息通知:祝你虎年大吉大利
    

    最后,点击查看示例代码

    个人公众号,喜欢的可以关注一下:
    在这里插入图片描述

    更多相关内容
  • redis发布订阅

    千次阅读 2022-03-23 10:02:21
    目录 一、概要 二、特点 三、发布及订阅功能 四、Redis发布订阅命令 ...Redis发布订阅(pub/sub)是一种消息通信模式:...Redis 发布订阅(pub/sub)实现了消息系统,发送者(在redis术语中称为发布者)在接收者(订阅者)...

    目录

    一、概要

    二、特点

    三、发布及订阅功能

    四、Redis发布订阅命令

    五、php实现redis发布-订阅

    1、消息发布端

    2、消息订阅端

    六、订阅发布使用场景

    七、在订阅时遇到错误

    八、模式匹配(正则匹配)订阅


    一、概要

            Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

            Redis 发布订阅(pub/sub)实现了消息系统,发送者(在redis术语中称为发布者)在接收者(订阅者)接收消息时发送消息。传送消息的链路称为信道。

    在Redis中,客户端可以订阅任意数量的信道。

    • 消息发布

    • 消息订阅

     

     

    二、特点

            发送者(发布者)不是计划发送消息给特定的接收者(订阅者)。而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅。

            订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的。

    这种发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑。

    三、发布及订阅功能

    1、 基于事件的系统中,Pub/Sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。

    2、 消息发布者,即publish客户端,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作(例如:INCR等)

    3、 消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;这一点很好理解,因此subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。

    # 订阅一个redisChat频道
    
    redis 127.0.0.1:6379> SUBSCRIBE redisChat  
    Reading messages... (press Ctrl-C to quit) 
    1) "subscribe" 
    2) "redisChat" 
    3) (integer) 1
    
    #发布消息到redisChat频道,发布成功后,订阅者会收到信息
    redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"  
    (integer) 1  
    redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by yiibai"  
    (integer) 1   
    1) "message" 
    2) "redisChat" 
    3) "Redis is a great caching technique" 
    1) "message" 
    2) "redisChat" 
    3) "Learn redis by yiibai"

    四、Redis发布订阅命令

    PUBLISH channel message	        #将信息发送到指定的频道。
    SUBSCRIBE channel [channel …]	#订阅给定的一个或多个频道的信息。
    UNSUBSCRIBE [channel [channel …]]	#退订给定的频道。
    
    PSUBSCRIBE pattern [pattern …]	#订阅一个或多个符合给定模式的频道。根据模式来订阅,可以订阅许多频道
    PUNSUBSCRIBE [pattern [pattern …]]	#退订所有给定模式的频道。
    
    PUBSUB subcommand [argument [argument …]]	#查看订阅与发布系统状态。

    五、php实现redis发布-订阅

    1、消息发布端

    <?php
    
    //消息发布
    $redis = new Redis();
    // 第一个参数为redis服务器的ip,第二个为端口
    $res = $redis->connect('121.41.88.209', 6379);
    // test为发布的频道名称,hello,world为发布的消息
    $res = $redis->publish('test','hello,world'.rand(00000,99999));

    2、消息订阅端

    <?php
    
    //消息订阅端
    $redis = new Redis();
    $res = $redis->pconnect('121.41.88.209', 6379);
    $redis->setOption(\Redis::OPT_READ_TIMEOUT,-1);
    $redis->subscribe(array('test'), 'callback');
    
    // 回调函数,这里写处理逻辑
    function callback($instance, $channelName, $message) {
     echo $channelName, "==>", $message,PHP_EOL;
    }
    

    六、订阅发布使用场景

            使用订阅频道达到解耦作用,场景:用户编辑某个模块需要清除缓存,可以在编辑模块后发布到频道,然后订阅该模块的清除缓存

    七、在订阅时遇到错误

    在命令执行redis订阅端脚本时,发现在终端会输出:

    PHP Fatal error:  Uncaught exception 'RedisException' with message 'read error on connection' in …

    这个错误大概的意思就是遇到了一个未捕获的异常:RedisException,消息读取错误当连接的时候。 应该是redis的客户端读取超时原因导致。 很多人在github上留言能不能提供一个类似php的pconnect的接口,但是貌似redis官方对这个没有一个官方的解决办法。

    错误解决办法(以下3种办法):

    【1】设置,default_socket_time = -1 但是本机测试的时候,应该是版本不一样的原因,直接报错:

    redis server went away

    【2】给redis connect的时候( pconnect( host,port = 6379, $timeout = 0.0 ))给timeout设置一个较大的值。

    【3】通过Redis自带的常量设置

    $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);

    八、模式匹配(正则匹配)订阅

    Redis 的Pub/Sub实现支持模式匹配。

    客户端可以订阅全风格的模式以便接收所有来自能匹配到给定模式的频道的消息。

    比如,将接收所有发到 test.name,test.phone,test.address...等等的消息,该这样写:

    PSUBSCRIBE test.*

    在终端回车后,同时再新的窗口里分别发布两个频道的消息,名字分别为:test.name和test.phone,然后切换到订阅端的窗口里,结果如下

    127.0.0.1:6379> PUBLISH test.name hehe
    (integer) 1
    127.0.0.1:6379> PUBLISH test.name haha
    (integer) 1

    由上图可以看出,在订阅了test.*频道后,一共收到了 test.name和test.phone两个频道的消息,这就是模式匹配订阅。

    3) "test.name"
    4) "haha"

    那么取消订阅匹配该模式的客户端也比较简单:

    PUNSUBSCRIBE test.*

    注意:不能在redis-cli中使用PUNSUBSCRIBE 取消退订,没有效果,指的是在php这些脚本中

    展开全文
  • 分布式通信:发布订阅

    万次阅读 2021-12-25 13:22:31
    分布式通信:发布订阅前言什么是发布订阅发布订阅的基本工作原理点对点模式发布订阅模式。Kafka 发布订阅原理及工作机制分区和消费组的原理和作用BrokerConsumer发布订阅实践应用知识扩展:观察者模式和发布订阅...


    前言

    分布式通信中的远程调用的核心是在网络服务层封装了通信协议、序列化、传输等操作,让用户调用远程服务如同进行本地调用一样。 通过网络服务层的封装实现了不同机器上不同进程之间的直接通信,因为是直接通信,所以通过线程阻塞的方式实现同步调用比较容易,因此通常被用于同步调用。比如,机器 1 上的进程 A 调用机器 2 上的进程 B,进程 A 被挂起,进程 B 开始执行,当进程 B 将值返回给 A 时,A 继续执行。

    虽然这种方式也可以用于异步通信,但因为进程之间是直接交互的,所以当进程比较多时, 会导致进程维护通信的复杂度非常高,且一个进程通信接口改变,与其通信的进程都会受到影响。

    随着业务和分布式计算规模的逐渐增大和复杂化,远程调用模型有点心有余力而不足了,为此出现了专门的异步通信模式,也就是消息发布订阅模式和消息队列模式。

    什么是发布订阅?

    发布订阅的思想在生活中随处可见。比如,学术届电子论文的订阅方式。通常各个会议方或出版社会将学术论文发布到论文网站(或平台上,比如 ACM、知网等),然后学生或老师向论文网站订阅自己感兴趣的论文。

    当会议方或出版社将论文发布到论文网站后,论文网站会根据订阅信息,将相应的论文推送给订阅者(比如通过邮件的方式)。这里的会议方或出版社就相当于生产者,负责发布论文,学生或老师就相当于消费者,而论文网站就相当于一个消息中心。

    在这里插入图片描述

    发布订阅的三要素是生产者、消费者和消息中心,生产者负责产生数据放到消息中心,消费者向消息中心订阅自己感兴趣的消息,当发布者推送数据到消息中心后,消息中心根据消费者订阅情况将相关数据推送给对应的订阅者。

    发布订阅的基本工作原理

    在分布式通信领域中,消息系统一般有两种典型的模式:

    1. 点对点模式(P2P,Point to Point)
    2. 发布订阅模式(Pub/Sub,Publish/Subscribe)。

    点对点模式

    生产者将消息发送到消息中心,然后消费者从消息中心取出对应的消息进行消费。消息被消费后,消息中心不再存储该消息,因此其他消费者无法再消费该消息。点对点模式虽然支持多个消费者,但一个消息只能被一个消费者消费,不允许重复消费。

    就好比限定了每篇论文只能被一个用户消费,比如现在有一篇分布式相关的论文,这篇论文推送给学生 A 之后,论文网站就必须将其删除或下架,其他用户无法再获取或阅读该论文了。
    在这里插入图片描述

    发布订阅模式。

    生产者可以发送消息到消息中心,而消息中心通常以主题(Topic)进行划分,每条消息都会有相应的主题,消息会被存储到自己所属的主题中,订阅该主题的所有消费者均可获得该消息进行消费。

    在这里插入图片描述

    假设生产者 1 发布一个 Topic 相关数据或消息,消费者 1~3 均订阅了该 Topic 消息,则该消息会推送消费者 1~3,同一个消息被 3 个消费者消费了。

    就好比不同的方向代表不同的主题,比如分布式领域代表一个主题,当会议方或出版社发布分布式相关的论文时,该论文会被存储到论文网站的分布式主题下,根据自己感兴趣的主题进行订阅。如果学生 A 订阅了分布式主题,那么当会议方或出版社发布分布式相关的论文后,会议网站会将这些论文推送给学生 A。

    与点对点模式相比,发布订阅模式中一个消息可以被多个消费者进行消费,这也是和点对点模式的本质区别。

    在分布式系统中,通常会为多用户服务,而多个用户通常会关注相同类型的消息,因此发布订阅模式在分布式系统中非常常见。

    Kafka 发布订阅原理及工作机制

    Kafka 是一种典型的发布订阅消息系统,其系统架构也是包括生产者、消费者和消息中心三 部分:

    • 生产者(Producer)负责发布消息到消息中心,比如电子论文的会议方或出版社;
    • 消费者(Consumer)向消息中心订阅自己感兴趣的消息,获得数据后进行数据处理, 比如订阅电子论文的老师或学生;
    • 消息中心(Broker)负责存储生产者发布的消息和管理消费者订阅信息,根据消费者订阅信息,将消息推送给消费者,比如论文网站。在 Kafka 中,消息中心本质上就是一组服务器,也可以说是 Kafka 集群。

    Kafka 的架构图,如下所示:

    在这里插入图片描述

    Kafka 中除了 Producer、Broker、Consumer 之外,还有一个 ZooKeeper 集群。Zookeeper 集群用来协调和管理 Broker 和 Consumer,实现了 Broker 和 Consumer 的解耦,并为系统提供可靠性保证。

    ZooKeeper 集群是一个提供了分布式服务协同能力的第三方组件,Consumer 和 Broker 启动时均会向 ZooKeeper 进行注册,由 ZooKeeper 进行统一管理和协调。

    ZooKeeper 中会存储一些元数据信息,比如对于 Broker,会存储主题对应哪些分区 (Partition),每个分区的存储位置等;对于 Consumer,会存储消费组(Consumer Group)中包含哪些 Consumer,每个 Consumer 会负责消费哪些分区等。

    分区和消费组的原理和作用

    Broker 负责存储消息数据,Consumer 负责消费数据, Consumer 消费数据的能力会影响 Broker 数据存储是否溢出的问题。若 Consumer 消费太慢,会导致 Broker 存储溢出,Broker 就会丢弃一部分消息。

    因此 Broker 和 Consumer 是 Kafka 的核心。如下图所示:

    在这里插入图片描述

    Broker

    在 Kafka 中,为了解决消息存储的负载均衡和系统可靠性问题,所以引入了主题和分区的概念。

    主题是一个逻辑概念,指的是消息类型或数据类型,就好比电子论文案例所讲的分布式是一个主题。

    分区是针对主题而言的,指的是一个主题的内容可以被划分成多个集合,分布在不同的 Broker 上,不同的 Broker 在不同的节点上。这里的集合就是分区,其中同一个分区只属于一个 Broker。

    分区的优点:

    • 实现负载均衡,避免单个 Broker 上的负载过高。比如,Topic 0 被分为 Partiton-0、 Partiton-1 和 Partiton-2 三个分区,分别分布在 Broker 0、Broker 1 和 Broker 2 上。 使 Topic 0 的消息可以分布在这 3 个分区中,实现负载均衡。
    • 实现消息的备份,从而保证系统的高可靠。比如,Topic 1 包含两个分区 Partiton-0、 Partiton-1,每个分区内容一致,分别存储在 Broker 0 和 Broker 1 上,借此实现了数据备份。

    Consumer

    Kafka 中的消费组,指的是多个消费者的一个集合。一个消费组中的消费者共同消费主题消息,并且主题中每个消息只可以由消费组中的某一个消费者进行消费。

    引入消费组的目的:在消息过多的情况下,单个消费者消费能力有限时,会导致消费效率过低,从而导致 Broker 存储溢出,丢弃一部分消息。

    发布订阅实践应用

    假设在电商购物平台中,用户首先在订单系统下单,下单后库存系统会进行出货,通知系统则负责通知用户,整个流程可以用发布订阅的模式进行,如下图所示:

    在这里插入图片描述

    订单系统对应发布订阅模式中的生产者,消息中心有个主题专门存放下单信息,每次用户下单后,订单系统会向该主题写入数据;库存系统和通知系统对应发布订阅模式中的消费者,它们会向消息中心订阅下单信息相关的主题;订单系统向消息中心发布订单信息后,库存系统和通知系统都会获取到相应的下单信息,然后进行各自后续的操作,即库存系统进行出货,通知系统通过短信或邮件等方式通知用户。

    发布订阅模式的关键特征

    • 实现了系统解耦,易于维护。生产者 / 发布者只负责消息的发布,不需要知道订阅者 / 消费者的数量,也不需要知道订阅者 / 消费者获取消息用来做什么,而订阅者 / 消费者也不需要知道什么时候生产者 / 发布者会发布消息。 所以生产者 / 发布者和订阅者 / 消费者互相独立,进而实现了系统解耦,每个部分可以单独维护,减少了因为生产者和消费者的耦合引入的一些相互影响。比如,如果两者耦合在 一起,当生产者逻辑更改需要修改代码时,消费者部分的代码也受影响,因此每个部分单独维护降低了维护的复杂度。

    • 实现了异步执行,避免高负载。生产者 / 发布者发布消息到消息中心,当消息超过消息中心可以存储的容量后,消息中心会丢弃掉超出的消息,这样系统就不会因为消息数量多而导致系统故障。

    知识扩展:观察者模式和发布订阅模式的区别是什么?

    观察者模式下有观察者,就有被观察者。观察者负责监控被观察者的状态变更,如果被观察者的状态发生了改变,观察者根据状态的变更执行相关操作。举个例子,现在进程 A 是被观察者,进程 B 和进程 C 是观察者, 当进程 B 观察到进程 A 中变量 X 由 3 变为 4 时,执行 X+1 的操作;当进程 C 观察到进程 A 中变量 X 由 3 变为 4 时,执行 X-1 的操作。观察者模式,定义了被观察者与观察者的直接交互或通信关系。

    发布订阅模式中存在发布者、订阅者和消息中心,订阅者需要向消息中心指定自己对哪些数据感兴趣,发布者推送的数据放入消息中心后,消息中 心根据订阅者订阅信息推送数据。发布者和订阅者之间引入了消息中心,实现的是间接通信。

    观察者模式采用了直接通信,观察者和被观察者通信时延会低一些,但它们的依赖关系比较强,不管是被观察者还是观察者逻辑或接口有更改,另外一个均会受影响。

    发布者和订阅者模式采用间接通信,引入了消息中心,相对比较厚重,且通信时延相对会高一 点,但实现了订阅者与发布者的解耦。

    总结

    发布订阅就是生产者产生消息发布到消息中心,消费者订阅自己感兴趣的消息,消息中心根据消费者的订阅情况将相关消息发给对应的消费者。

    Kafka 是一个经典的发布订阅消息系统,采用多分区实现了消息备份、负载均衡,并引入消费组提高了消费者的消费能力,防止 Broker 因为存储资源不够丢弃消息的情况,从而提高了 Kafka 系统的可靠性。

    发布订阅模式可以使系统松耦合易于维护,也可异步执行解决高负载问题,适用于系统解耦、流量削峰等场景。

    在这里插入图片描述

    发布订阅模式易于理解,与点对点模式很类似。不同的是,点对点模式中一个消息只能由一 个消费者消费,而发布者订阅者模式中一个消息可以由多个消费者消费。

    不同的通信模式适用于不同的分布式场景,其中发布订阅模式适合具备多个生产者、多个消费者且异步处理的场景,比如现在的视频 App,多个用户都可以通过同一款 App 看同一部电视剧,当然这个电视剧可以是被不同的生产者发布。点对点模式由于其局限性,一般适用于需要进行点对点通信的场景,比如近场投屏等。

    展开全文
  • 深入Vue原理_全面剖析发布订阅模式

    千次阅读 多人点赞 2022-04-01 11:07:05
    文章目录发布订阅模式优化优化思路思考理解发布订阅模式(自定义事件)收集更新函数触发更新函数6.5 总结总结写在最后 上节中我们提到下方更新的问题:无法做到精准更新 <div id="app"> <p v-text="name"&...

    欢迎各位小伙伴们!
    为大家推荐一款刷题神奇哦 点击链接访问牛客网
    各大互联网大厂面试真题。从基础到入阶乃至原理刨析类面试题 应有尽有,赶快来装备自己吧!助你面试稳操胜券,solo全场面试官
    上节中我们提到下方更新的问题:无法做到精准更新

    <div id="app">
      <p v-text="name"></p>
      <p v-text="age"></p>
      <p v-text="name"></p>
    </div>
    <script>
      let data = {
        name: '小兰同学',
        age: 18,
        height: 180
      }
      // 遍历每一个属性
      Object.keys(data).forEach((key) => {
        // key 属性名
        // data[key] 属性值
        // data 原对象
        defineReactive(data, key, data[key])
      })
      function defineReactive(data, key, value) {
        Object.defineProperty(data, key, {
          get() {
            return value
          },
          set(newVal) {
            // 数据发生变化,操作dom进行更新
            if (newVal === value) {
              return
            }
            value = newVal
            compile()
          }
        })
      }
      // 编译函数
      function compile() {
        let app = document.getElementById('app')
        // 1.拿到app下所有的子元素
        const nodes = app.childNodes   //  [text, input, text]
        //2.遍历所有的子元素
        nodes.forEach(node => {
          // nodeType为1为元素节点
          if (node.nodeType === 1) {
            const attrs = node.attributes
            Array.from(attrs).forEach(attr => {
              const dirName = attr.nodeName
              const dataProp = attr.nodeValue
              console.log( dirName,dataProp)
              if (dirName === 'v-text') {
                console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`)
                node.innerText = data[dataProp]
              }
            })
          }
        })
      }
      // 首次渲染
      compile()
    </script>
    

    发布订阅模式优化

    优化思路思考

    1.数据更新之后实际上需要执行的代码是什么?

    node.innerText = data[dataProp]
    

    为了保存当前的node和dataProp,我们再次设计一个函数执行利用闭包函数将每一次编译函数执行时候的node和dataProp都缓存下来,所以每一次数据变化之后执行的是这样的一个更新函数

    () => {
      node.innerText = data[dataProp]
    }
    

    2.一个响应式数据可能会有多个视图部分都需要依赖,也就是响应式数据变化之后,需要执行的更新函数可能不止一个,如下面的代码所示,name属性有俩个div元素都使用了它,所以当name变化之后,俩个div节点都需要得到更新,那属性和更新函数之间应该是一个一对多的关系

    <div id="app">
       <div v-text="name"></div>
       <div v-text="name"></div>
       <p v-text="age"></p>
       <p v-text="age"></p>
    </div>
    
    <script>
      let data = {
         name: 'cp',
         age: 18
      }
    </script>
    

    经过分析我们可以得到下面的存储架构图,每一个响应式属性都绑定了相对应的更新函数,是一个一对多的关系,数据发生变化之后,只会再次执行和自己绑定的更新函数

    在这里插入图片描述

    理解发布订阅模式(自定义事件)

    理解发布订阅,关键是理解一对多

    1. 从浏览器事件说起

    dom绑定事件的方式,我们学过俩种

    1. dom.onclick = function(){}
    2. dom.addEventListener(‘click’,()=>{})

    这俩种绑定方式的区别是,第二种方案可以实现同一个事件绑定多个回调函数,很明显这是一个一对多的场景,既然浏览器也叫作事件,我们试着分析下浏览器事件绑定实现的思路

    1. 首先addEventListenr是一个函数方法,接受俩个参数,分别是事件类型回调函数

    2. 因为是一个事件绑定多个回调函数,那在内存里大概会有这样的一个数据结构

      {
        click: ['cb1','cb2',....],
        input: ['cb1','cb2',...]
      }
      
    3. 触发事件执行,浏览器因为有鼠标键盘输入可以触发事件,大概的思路是通过事件名称找到与之关联的回调函数列表,然后遍历执行一遍即可

    ok,我们分析了浏览器事件的底层实现思路,那我们完全可以自己模仿一个出来,事件的触发,我们也通过设计一个方法来执行

    2. 实现简单的发布订阅

    // 增加dep对象 用来收集依赖和触发依赖
    const dep = {
        map: Object.create(null),
        // 收集
        collect(dataProp, updateFn) {
          if (!this.map[dataProp]) {
            this.map[dataProp] = []
          }
          this.map[dataProp].push(updateFn)
        },
        // 触发
        trigger(dataProp) {
          this.map[dataProp] && this.map[dataProp].forEach(updateFn => {
            updateFn()
          })
        }
    }
    

    收集更新函数

    在编译函数执行的时候,我们把用于更新dom的更新函数收集起来

     // 编译函数
      function compile() {
        let app = document.getElementById('app')
        // 1.拿到app下所有的子元素
        const nodes = app.childNodes   //  [text, input, text]
        //2.遍历所有的子元素
        nodes.forEach(node => {
          // nodeType为1为元素节点
          if (node.nodeType === 1) {
            const attrs = node.attributes
            // 遍历所有的attrubites找到 v-model
            Array.from(attrs).forEach(attr => {
              const dirName = attr.nodeName
              const dataProp = attr.nodeValue
              console.log(dirName, dataProp)
              if (dirName === 'v-text') {
                console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`)
                node.innerText = data[dataProp]
                // 收集更新函数
                dep.collect(dataProp, () => {
                  node.innerText = data[dataProp]
                })
              }
            })
          }
        })
     }
    

    触发更新函数

    当属性发生变化的时候,我们通过属性找到对应的更新函数列表,然后依次执行即可

    function defineReactive(data, key, value) {
        Object.defineProperty(data, key, {
          get() {
            return value
          },
          set(newValue) {
            // 更新视图
            if (newValue === value) return
            value = newValue
            // 再次编译要放到新值已经变化之后只更新当前的key
            dep.trigger(key)
          }
        })
    }
    

    6.5 总结

    1. 了解了发布订阅模式的基础形态
    2. 了解发布订阅可以解决什么样的具体问题(精准更新)

    总结

    1. 数据响应式的实现无非是对象属性拦截,我们使用Object.defineProperty来实现,在vue3中使用Proxy对象代理方案进行了优化,解决了Object.defineProperty存在的缺陷

    2. observe对象指的是把数据处理成响应式的对象

      watcher指的其实就是数据变化之后的更新函数 (Vue中的watcher有两种,一种是用来更新视图的watcher,一种是通过watch配置项声明的watcher)

      dep指的就是使用发布订阅实现的收集更新函数和触发更新函数的对象

    3. 指令实现的核心无非是通过模板编译找到标识然后把数据绑上去,等到数据变化之后再重新放一次

    4. 发布订阅模式的本质是解决一对多的问题,在vue中实现数据变化之后的精准更新

    写在最后

    原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下}

    👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!}

    ⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!}

    ✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!}

    本期推荐

    在这里插入图片描述

    【内容简介】
      本书以理论结合编程开发为原则,使用Python作为开发语言,讲解化算法的原理和应用,详细介绍了Python基础、Gurobi 优化器、线性规划、整数规划、多目标优化、动态规划、图与网络分析、智能优化算法。对于算法部分的每一种算法都包含原理和编程实践,使读者对化算法的认识更加深入。
     
      本书分为 3 篇共 9 章。第 1 篇(第 1~3 章)是化算法与编程基础:第 1 章介绍了什么是化算法及其在生产和生活中的应用;第 2章介绍Python编程基础和Python数据分析库及绘图库;第 3章讲解Gurobi 优化器的基础和高级特性。第 2篇(第 4~6章)是数学规划方法:第 4章详细讲解线性规划的知识,包括单纯形法、内点法、列生成法、拉格朗日乘子法、对偶问题;第 5 章讲解整数规划解法的分支定界法和割平面法;第 6 章讲解多目标优化的概念及基于单纯形法的目标规划法。第 3 篇(第 7~9 章)是启发式算法:第 7 章介绍动态规划算法;第 8 章讲解图与网络分析,介绍*小生成树、短路径、网络流、路径规划等问题的建模;第 9 章讲解了粒子群算法和遗传算法求解各种类型优化算法问题的方法。
      本书内容丰富,实例典型,实用性强,适合各个层次从事
    化算法研究和应用的人员,尤其适合有一定算法基础而没有编程基础的人员阅读。

    【作者简介】
      苏振裕,厦门大学金融学硕士,现任SHEIN 智慧供应链资深算法工程师。知乎专栏《从推公式到写代码》作者,运筹优化论坛(optimize.fun)创建人。在大数据、人工智能、运筹优化和供应链方面,具有多年的相关算法研究应用经验。

    展开全文
  • Redis进阶——发布订阅详解

    千次阅读 2021-11-23 13:12:17
    什么是发布订阅? Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。 Redis 的 subscribe 命令可以让客户端订阅任意数量的频道, 每当有新信息发送到被订阅的频道时, ...
  • 发布订阅模式

    千次阅读 2022-01-26 17:05:53
    什么是发布订阅模式? 此模式分为发布者和订阅者两个概念,发布者收集订阅者的需求,然后在某个时刻告知订阅者 例子: 小王去小卖部买充电器,小李去小卖部买剃须刀,但是充电器和剃须刀都卖完了,于是他们在小卖部...
  • 发布订阅模式与观察者模式

    万次阅读 多人点赞 2019-03-29 18:25:12
    网上关于这个问题的回答,出现了两极分化,有认为发布订阅模式就是观察者模式的,也有认为观察者模式和发布订阅模式是真不一样的。 其实我不知道发布订阅模式是不是观察者模式,就像我不知道辨别模式的关键是设计...
  • 文章目录Redis发布订阅功能介绍使用redis-cli客户端测试Redis发布订阅生产使用场景java代码demo消息订阅者消息订阅 线程类消息发布类Spring Boot启动类功能和性能测试功能测试性能测试 Redis发布订阅功能介绍 Redis...
  • Redis的发布订阅模式

    千次阅读 2021-12-14 19:52:10
    Redis发布订阅模式的总结及使用
  • SpringBoot整合redis实现发布订阅模式

    千次阅读 2022-04-15 12:45:47
    Redis的发布订阅模式 发布订阅(Pub/Sub):目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或...
  • React 中的发布订阅模式

    千次阅读 2022-02-27 12:03:01
    发布订阅模式
  • Redis发布订阅模式实现原理

    千次阅读 2022-03-09 14:55:05
    发布订阅系统在我们日常的工作中经常会使用到,这种场景大部分情况我们都是使用消息队列,常用的消息队列有 Kafka,RocketMQ,RabbitMQ,每一种消息队列都有其特性,很多时候我们可能不需要独立部署相应的消息队列,...
  • 针对网络上的sql server的发布订阅,进行了验证,发现只是进行了基本的发布订阅操作,但是对使用环境和使用前提都没做出说明,此文档增加了对环境设置的操作步骤
  • Redis的发布订阅

    千次阅读 2022-03-31 15:23:47
    发布订阅 Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。 Redis 客户端可以订阅任意数量的频道。 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— ...
  • 学习TypeScript22(实战TS编写发布订阅模式)

    千次阅读 多人点赞 2022-01-28 14:42:24
    什么是发布订阅模式,其实小伙伴已经用到了发布订阅模式例如addEventListener,Vue evnetBus 都属于发布订阅模式 简单来说就是 你要和 大傻 二傻 三傻打球,大傻带球,二傻带水,三傻带球衣。全都准备完成后开始...
  • Vue发布订阅模式

    2022-04-23 21:41:44
    我的回答:“发布订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知。具体过程就是订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到...
  • vue2数据响应式原理之依赖收集和发布订阅前言收集依赖,发布订阅依赖是谁?什么是Watcher?Watcher.jsDep.jsObserver.jsdefineReactive.js 前言 前几篇我们已经研究过了数据劫持,并多次提到依赖这个词,这一篇我们...
  • SqlServer 数据库发布订阅

    千次阅读 2021-11-22 15:46:30
    决定把实体服务器中的数据库数据通过发布订阅,拷贝到云数据库中,从而达到不停机切换服务。具体操作步骤如下。 一、实体机服务器中的数据库A 作为发布服务器 1.数据库发布订阅的时候,都必须使用实例名的方式登录...
  • springboot实现发布订阅

    千次阅读 2022-01-04 22:08:08
    springboot中实现发布订阅中主要的组成部分有:事件、发布者、订阅者;对应需要使用到的类分别是 ApplicationEvent、ApplicationContext和ApplicationListener。 1 事件 @Data public class ListenEvent extends ...
  • Linux编程MQTT实现主题发布订阅

    千次阅读 2022-02-14 08:47:02
    【物联网阿里云平台开发项目实战|附课件资料】智能硬件开发-数据上云,零基础入门 4G模块连接阿里云教程 MQTT通信协议(mosquitto)在Linux上的环境构建与测试 MQTT通信协议(mosquitto)发布订阅例子C语言实现 MQTT...
  • RabbitMQ 之发布订阅模式

    千次阅读 2022-04-19 18:38:31
    发布订阅模式中,生产者不再直接与队列绑定,而是将数据发送至交换机Exchange 交换机Exchange用于将数据按某种规则送入与之绑定的队列,进而供消费者使用。 发布订阅模式中,交换机将无差别的将所有消息送入与之绑定...
  • Vue 发布订阅模式

    千次阅读 2021-09-23 08:43:26
    发布订阅模式:订阅者,发布者,信号中心 我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己...
  • kafka 发布订阅 这是第四个柱中的一系列关于同步客户端集成与异步系统( 1, 2, 3 )。 在这里,我们将尝试了解Kafka的工作方式,以便正确利用其发布-订阅实现。 卡夫卡概念 根据官方文件 : Kafka是一种...
  • 实现一个简单的发布订阅模式

    千次阅读 2022-03-21 15:25:38
    文章目录一、发布订阅模式是什么?二、发布订阅模式的优缺点三、实现一个通用的发布订阅模式 一、发布订阅模式是什么? 发布订阅模式是对象间的一种一对多的关系,由发布者、订阅者、消息管理器三部分组成,让多个...
  • javascript 如何简单的实现发布订阅

    千次阅读 2022-04-18 15:48:33
    带你轻松实现发布订阅
  • Dapr专题之05发布订阅

    千次阅读 2022-03-04 13:55:19
    Dapr发布订阅 文章目录Dapr发布订阅Dapr发布订阅的优势调用终结点使用默认的Redis运行与测试切换RabbitMQ测试总结 提示:以下是本篇文章正文内容,下面案例可供参考 Dapr发布订阅的优势 可插拔的存储组件 支持...
  • js代码-实现发布/订阅模式
  • 观察者模式VS发布订阅模式

    千次阅读 2022-04-03 23:42:00
    观察者模式vs发布/订阅模式很容易混淆,像是凤梨和菠萝,傻傻分不清。Observer模式通常用Publish/Subscribe模式实现,我刚开始学习js的时候,以为这是同一回事,但是仔细学习,发现它们是有质的区别的。 二、观察者...
  • mqtt发布订阅,使用方法:1)开始mqtt服务端;2编译fake_user_publish和fake_user_sub;3运行两个可执行文件;效果:当fake_user_publish发布一个内容时,fake_user_sub订阅进程会收到相关的topic和payload。验证...
  • RedisTemplate实现发布订阅

    千次阅读 2021-02-05 16:24:09
    由于考虑到网关的纯洁性,所以使用feign调用的方式直接pass掉了,使用消息中间件也是一个好办法(但是项目安装比较麻烦因为你是政府项目),所以就想到了用redis的发布订阅的模式。 2.1订阅配置 频道常量 public...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 271,346
精华内容 108,538
关键字:

发布订阅

友情链接: wuziqi.rar