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

article/2025/10/27 0:27:49

文章目录

    • 发布订阅模式优化
      • 优化思路思考
      • 理解发布订阅模式(自定义事件)
      • 收集更新函数
      • 触发更新函数
      • 6.5 总结
    • 总结
    • 写在最后
    • 本期推荐

欢迎各位小伙伴们!
为大家推荐一款刷题神奇哦 点击链接访问牛客网
各大互联网大厂面试真题。从基础到入阶乃至原理刨析类面试题 应有尽有,赶快来装备自己吧!助你面试稳操胜券,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 = newValcompile()}})}// 编译函数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.attributesArray.from(attrs).forEach(attr => {const dirName = attr.nodeNameconst dataProp = attr.nodeValueconsole.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-modelArray.from(attrs).forEach(attr => {const dirName = attr.nodeNameconst dataProp = attr.nodeValueconsole.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) returnvalue = newValue// 再次编译要放到新值已经变化之后只更新当前的keydep.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)创建人。在大数据、人工智能、运筹优化和供应链方面,具有多年的相关算法研究应用经验。


http://chatgpt.dhexx.cn/article/VQUdsEpK.shtml

相关文章

观察者模式VS发布订阅模式区别

观察者模式VS发布订阅模式区别 观察者模式&#xff1a;订阅者收集函数&#xff0c;发布者循环调用 发布订阅&#xff1a;收集发布单独给一个中介 对比 以结构来分辨模式&#xff0c;发布订阅模式相比观察者模式多了一个调度中心&#xff1b; 以意图来分辨模式&#xff0c;都…

RabbitMQ:发布订阅模式

✨ RabbitMQ:发布订阅模式 1.订阅模式基本介绍2.交换机3.发布订阅模式3.1基本介绍3.2生产者3.3消费者3.4测试 &#x1f4c3;个人主页:不断前进的皮卡丘 &#x1f31e;博客描述:梦想也许遥不可及&#xff0c;但重要的是追梦的过程&#xff0c;用博客记录自己的成长&#xff0c;记…

JavaScript设计模式:四、发布订阅模式

JavaScript设计模式&#xff1a;四、发布订阅模式 文章目录 JavaScript设计模式&#xff1a;四、发布订阅模式一、概述1. 观察者模式2. 发布订阅模式3. 观察者模式是不是发布订阅模式 一、概述 观察者模式&#xff1a; 观察者&#xff08;Observer&#xff09;直接订阅&#x…

发布订阅模式理解

发布订阅模式理解 1.发布-订阅模式 发布订阅模式是一种一对多的对象对应关系&#xff0c;多个观察者同时监听某一个对象&#xff0c;当该对象发生改变时&#xff0c;就会执行一个发布事件&#xff0c;这个发布事件会通知所有的事件订阅者&#xff0c;事件订阅者根据得到的数据…

JS观察者模式和发布订阅模式

观察者模式 观察者模式在前端工程中是很常见的设计模式&#xff0c;因为前端交互中充斥着大量多控件联动的交互&#xff0c;当参与联动的组件数量比较多或者组件数量可能变化的时候&#xff0c;代码就会变得难以维护。但是如果我们写代码时遵循了观察者模式的设计&#xff0c;…

redis发布订阅模式详解

文章目录 写在前面发布订阅的使用SUBSCRIBE命令PUBLISH命令注意发布、订阅客户端启动顺序&#xff01; PUBSUB命令PUNSUBSCRIBE命令UNSUBSCRIBE命令PSUBSCRIBE命令 总结 写在前面 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订…

Vue发布订阅模式

简单的来说一下在别人问你这个问题的时候怎么来回答它 前端新人&#xff0c;如有错误求大佬指出~求教&#x1f49d; 情景复现 大佬提问&#xff1a;“你知道Vue发布订阅模式是什么吗&#xff1f;" 我的回答&#xff1a;“发布订阅模式其实是一种对象间一对多的依赖关系&…

观察者模式和发布订阅模式

一、概念 观察者(Observer)&#xff0c;又称发布-订阅&#xff08;Publish-Subscrice&#xff09;&#xff0c;属于23中设计模式之一。 发布订阅模式定义了一种一对多的依赖关系&#xff0c;让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时&#xff0c…

C++发布订阅模式

C发布订阅模式 发布订阅模式主要包含三个部分&#xff1a;消息发布、消息订阅者、消息处理中心。与观察者模式相比多出了消息处理中心模块&#xff0c;这样在结构上可以解耦订阅者与发布者&#xff0c;功能上更加的丰富。 观察者模式 结构设计 有一个消息list&#xff0c;主…

Java实现发布订阅模式

什么是发布订阅模式 发布订阅模式是软件开发者很常见的一种设计模式&#xff0c;很多开源库都使用了发布订阅模式&#xff0c;例如RxJava、EventBus、Vue等&#xff0c;所以学习该模式还是很有必要的。 该模式中存在一个或多个发布者&#xff0c;一个或多个订阅者&#xff0c…

设计模式 —— 发布订阅模式

设计模式 —— 发布订阅模式 《工欲善其事&#xff0c;必先利其器》 我在之前有写过一篇关于 《观察者模式》 的文章&#xff0c;大家有兴趣的可以去看看&#xff0c;个人认为那个例子还是挺生动的。&#xff08;狗头&#xff09; 不过今天我们要学习的是&#xff0c;发布订阅…

小侃设计模式(十八)-发布订阅模式

1.概述 发布订阅模式又叫观察者模式&#xff08;Observer Pattern&#xff09;&#xff0c;它是指对象之间一对多的依赖关系&#xff0c;每当那个特定对象改变状态时&#xff0c;所有依赖于它的对象都会得到通知并被自动更新&#xff0c;它是行为型模式的一种。观察者模式内部…

发布-订阅模式

发布-订阅模式 学习知识要善于思考&#xff0c;思考&#xff0c;再思考。 —— 爱因斯在众多设计模式中&#xff0c;可能最常见、最有名的就是发布 - 订阅模式了&#xff0c;本篇我们一起来学习这个模式。 发布 - 订阅模式 &#xff08;Publish-Subscribe Pattern, pub-sub&a…

什么是发布订阅模式?

发布-订阅模式&#xff08;Publish-Subscribe pattern&#xff09;是一种软件架构模式&#xff0c;用于实现组件之间的解耦和消息传递。在这种模式中&#xff0c;组件&#xff08;发布者&#xff09;将消息发送到一个中心&#xff08;消息代理或主题&#xff09;&#xff0c;然…

发布订阅模式

零、目录 应用场景实现原理代码实现全局模式下的订阅发布模式&#xff08;泛化的订阅发布模式&#xff09;总结 一、应用场景 ​ 发布订阅模式&#xff0c;广泛的存在于在我们的生活之中。 ​ 举个一个简单的例子来说&#xff0c;当我们在浏览视频或者博客论坛之类的网…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:VLCPlayer

本文简述如何在Smobiler中使用VLCPlayer插件&#xff0c;该插件支持播放rtsp流。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入VLCPlay&#xff0c;布局如下 在设计器中给VLCPlayer.Url赋值或者在窗体的Load事件中赋值 演示使用的rtsp流地址 rtsp://wowzaec2demo.strea…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:TTS

本文简述如何在Smobiler中使用TTS文字转语音。 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入TTS和Button&#xff0c;布局如下 Button的点击事件代码&#xff1a; private void button1_Press(object sender, EventArgs e){ //第一个参数为文本&#xff1b;第…

Smobiler 仿得到APP个人主页

原型如下&#xff1a; 完整代码参考 https://github.com/comsmobiler/BlogsCode/blob/master/Source/BlogsCode_SmobilerForm/MyForm/dedao.cs 思路 可以将原型按照上图分成2个部分&#xff0c;部分A可以使用label、image、button、imagebutton、fontIcon控件来实现&#xff…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:PDFView

本文简述如何在Smobiler中使用PDFView。 Step 1. 新建一个SmobilerForm窗体&#xff0c;再拖入PDfView&#xff0c;布局如下 PDFView.ResourcrPath默认Document&#xff0c;指项目下\Resources\Document&#xff0c;若是pdf文件放在该文件夹下&#xff0c;则在设计器中直接赋值…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:OCR组件

本文简述如何在Smobiler中使用OCR组件进行文字识别。 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入OCR和Button&#xff0c;布局如下 Button的点击事件代码&#xff1a; private void button1_Press(object sender, EventArgs e){ocr1.Recognize((obj,args)>…