Vue3响应式原理

关注若川视野,回复"pdf" 领取资料,回复"加群",可加群长期交流学习

本文结构

    - 关于Vue3

    - Vue2响应式原理回顾

    - Vue3响应式方案

    - Vue3响应式原理

    - 手写mini版Vue3响应式

本文共计:2349字2图

预计阅读时间:4min30s

关于Vue3

话说,Vue3已经进行到rc4版本了,4月份beta发布的时候前端圈红红火火

不会吧不会吧,不会你还没开始学吧????

整理了一些资源,现在开始学习应该还不算晚

  • vue-next仓库[1]

  • 20200723 Vue3 官方发布的beta文档[2]

  • Vue3 Roadmap & FAQ[3]

  • Vue3仓库已经合并的780多个PR[4]

  • 尤大在Vue Mastery的Vue3课:Vue 3 Deep Dive with Evan You[5]

  • 202007 尤大在前端会客厅节目关于Vue3的访谈[6]

  • 202005 The process: Making Vue 3[7]

  • 202004 尤大 - 聊聊 Vue.js 3.0 Beta 官方直播[8]

  • 2018 VueConf 杭州 尤大关于Vue3的演讲视频[9]

拉到文章底部找到上述链接,以下正文探讨一下Vue3响应式原理

Vue2 响应式原理回顾

  • 对象响应化:遍历每个key,通过 Object.defineProperty API定义getter,setter

// 伪代码
function observe(){if(typeof obj !='object' || obj == null){return}if(Array.isArray(obj)){Object.setPrototypeOf(obj,arrayProto)}else{const keys = Object.keys()for(let i=0;i<keys.length;i++){const key = keys[i]defineReactive(obj,key,obj[key])}}
}
function defineReactive(target, key, val){observe(val)Object.defineProperty(obj, key, {get(){// 依赖收集dep.depend()return val},set(newVal){if(newVal !== val){observe(newVal)val = newVal// 通知更新dep.notify()}}})
}
  • 数组响应化:覆盖数组的原型方法,增加通知变更的逻辑

// 伪代码
const originalProto = Array.prototype
const arrayProto = Object.create(originalProto)
['push','pop','shift','unshift','splice','reverse','sort'].forEach(key=>{arrayProto[key] = function(){originalProto[key].apply(this.arguments)notifyUpdate()}
})

vue2响应式痛点

  • 递归,消耗大

  • 新增/删除属性,需要额外实现单独的API

  • 数组,需要额外实现

  • Map Set Class等数据类型,无法响应式

  • 修改语法有限制

vue3响应式方案

使用ES6的 `Proxy`[10] 进行数据响应化,解决上述Vue2所有痛点

Proxy可以在目标对象上加一层拦截/代理,外界对目标对象的操作,都会经过这层拦截

相比 Object.defineProperty ,Proxy支持的对象操作十分全面:get、set、has、deleteProperty、ownKeys、defineProperty......等等

// reactive 伪代码
function reactice(obj){return new Proxy(obj,{get(target, key, receiver){const ret = Reflect.get(target, key, receiver)return isObject(ret) ? reactice(ret) : ret},set(target, key, val, receiver){const ret = Reflect.set(target, key, val, receiver)return ret},deleteProperty(target, key){const ret = Reflect.deleteProperty(target, key)return ret},})
}

Vue3响应式原理

vue3响应式原理图
  • 通过 effect  声明依赖响应式数据的函数cb ( 例如视图渲染函数render函数),并执行cb函数,执行过程中,会触发响应式数据 getter

  • 在响应式数据 getter中进行 track依赖收集:建立 数据&cb 的映射关系存储于 targetMap

  • 当变更响应式数据时,触发 trigger **,**根据 targetMap 找到关联的cb执行

  • 映射关系 targetMap 结构:

targetMap: WeakMap{ target:Map{ key: Set[cb1,cb2...] }
}

手写vue3响应式

大致结构

// mini-vue3.js/* 建立响应式数据 */
function reactice(obj){}/* 声明响应函数cb(依赖响应式数据) */
function effect(cb){}/* 依赖收集:建立 数据&cb 映射关系 */
function track(target,key){}/* 触发更新:根据映射关系,执行cb */
function trigger(target,key){}

reactive

/* 建立响应式数据 */
function reactive(obj){// Proxy:http://es6.ruanyifeng.com/#docs/proxy// Proxy相当于在对象外层加拦截// Proxy递归是惰性的,需要添加递归的逻辑// Reflect:http://es6.ruanyifeng.com/#docs/reflect// Reflect:用于执行对象默认操作,更规范、更友好,可以理解成操作对象的合集// Proxy和Object的方法Reflect都有对应if(!isObject(obj)) return objconst observed = new Proxy(obj,{get(target, key, receiver){const ret = Reflect.get(target, key, receiver)console.log('getter '+ret)// 跟踪 收集依赖track(target, key)return reactive(ret)},set(target, key, val, receiver){const ret = Reflect.set(target, key, val, receiver)console.log('setter '+key+':'+val + '=>' + ret)// 触发更新trigger(target, key)return ret},deleteProperty(target, key){const ret = Reflect.deleteProperty(target, key)console.log('delete '+key+':'+ret)// 触发更新trigger(target, key)return ret},})return observed
}

effect

/* 声明响应函数cb */
const effectStack = []
function effect(cb){// 对函数进行高阶封装const rxEffect = function(){// 1.捕获异常// 2.fn出栈入栈// 3.执行fntry{effectStack.push(rxEffect)return cb()}finally{effectStack.pop()}}// 最初要执行一次,进行最初的依赖收集rxEffect()return rxEffect
}

track

/* 依赖收集:建立 数据&cb 映射关系 */
const targetMap = new WeakMap()
function track(target,key){// 存入映射关系const effectFn = effectStack[effectStack.length - 1]  // 拿出栈顶函数if(effectFn){let depsMap = targetMap.get(target)if(!depsMap){depsMap = new Map()targetMap.set(target, depsMap)}let deps = depsMap.get(key)if(!deps){deps = new Set()depsMap.set(key, deps)}deps.add(effectFn)}
}

trigger

/* 触发更新:根据映射关系,执行cb */
function trigger(target, key){const depsMap = targetMap.get(target)if(depsMap){const deps = depsMap.get(key)if(deps){deps.forEach(effect=>effect())}}
}

测试demo

<!-- test.html -->
<div id="app">{{msg}}
</div><script src="./mini-vue3.js"></script><script>// 定义一个响应式数据const state = reactive({msg:'message'})// 定义一个使用到响应式数据的 dom更新函数function updateDom(){document.getElementById('app').innerText = state.msg}// 用effect声明更新函数effect(updateDom)// 定时变更响应式数据setInterval(()=>{state.msg = 'message' + Math.random()},1000)
</script>

效果:

测试效果

如果想获取上述代码,放在了这个仓库:mini-vue3-reactive[11]

参考资料

[1]

vue-next仓库: https://github.com/vuejs/vue-next

[2]

20200723 Vue3 官方发布的beta文档: https://v3.vuejs.org/

[3]

Vue3 Roadmap & FAQ: https://github.com/vuejs/vue/projects/6

[4]

Vue3仓库已经合并的780多个PR: https://github.com/vuejs/vue-next/pulls?q=is%3Apr+is%3Amerged

[5]

尤大在Vue Mastery的Vue3课:Vue 3 Deep Dive with Evan You: https://www.vuemastery.com/courses/vue3-deep-dive-with-evan-you/vue3-overview

[6]

202007 尤大在前端会客厅节目关于Vue3的访谈: https://www.bilibili.com/video/BV1qC4y18721

[7]

202005 The process: Making Vue 3: https://increment.com/frontend/making-vue-3/

[8]

202004 尤大 - 聊聊 Vue.js 3.0 Beta 官方直播: https://www.bilibili.com/video/BV1Tg4y1z7FH

[9]

2018 VueConf 杭州 尤大关于Vue3的演讲视频: https://www.bilibili.com/video/BV1Et41197L4

[10]

Proxy: https://es6.ruanyifeng.com/#docs/proxy

[11]

仓库:mini-vue3-reactive: https://github.com/scarsu/mini-vue3-reactive

- END -

推荐阅读

我在阿里招前端,我该怎么帮你?(文末有福利)
如何拿下阿里巴巴 P6 的前端 Offer
如何准备阿里P6/P7前端面试--项目经历准备篇
大厂面试官常问的亮点,该如何做出?
如何从初级到专家(P4-P7)打破成长瓶颈和有效突破
若川知乎问答:2年前端经验,做的项目没什么技术含量,怎么办?

末尾

你好,我是若川,江湖人称菜如若川,历时一年只写了一个学习源码整体架构系列~(点击蓝字了解我)

  1. 关注若川视野,回复"pdf" 领取优质前端书籍pdf,回复"加群",可加群长期交流学习

  2. 我的博客地址:https://lxchuan12.gitee.io 欢迎收藏

  3. 觉得文章不错,可以点个在看呀^_^另外欢迎留言交流~

小提醒:若川视野公众号面试、源码等文章合集在菜单栏中间【源码精选】按钮,欢迎点击阅读,也可以星标我的公众号,便于查找

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

找准切入点,调试看源码,事半功倍

关注若川视野&#xff0c;回复"pdf" 领取资料&#xff0c;回复"加群"&#xff0c;可加群长期交流学习最近写了很多源码分析相关的文章&#xff0c;React、Vue 都有&#xff0c;想把我阅读源码的一些心得分享给大家。React&#xff1a;React 架构的演变 - 从…

Android布局大全

Android的界面是有布局和组件协同完成的&#xff0c;布局好比是建筑里的框架&#xff0c;而组件则相当于建筑里的砖瓦。组件按照布局的要求依次排列&#xff0c;就组成了用户所看见的界面。 所有的布局方式都可以归类为ViewGroup的5个类别&#xff0c;即ViewGroup的5个直接子类…

java实现加减乘除运算符随机生成十道题并判断对错_2020年Java面试题(3年的工作总结),最全的知识点总结...

这份Java面试题整整花了三个月的时间来整理&#xff0c;都是自己再工作中总结出来&#xff0c;记住多少就写多少&#xff0c;希望这份资料可以帮助你们&#xff0c;文末有其余部分资料的领取方式.Redis12道面试题1.什么是Redis&#xff1f;答&#xff1a;Remote Dictionary Ser…

.NET 中的泛型 101

1.1.1 摘要 图1 C# 泛型介绍 在接触泛型之前&#xff0c;我们编程一般都是使用具体类型&#xff08;char, int, string等&#xff09;或自定义类型来定义我们变量&#xff0c;如果我们有一个功能很强的接口&#xff0c;而且我们想把它提取或重构成一个通用的接口&#xff0c;使…

年底了,给想进阶的的前端朋友一些福利

2020 年&#xff0c;很多朋友都经历了一段比较艰难的求职季。年末&#xff0c;“就业寒冬”迎来了一丝暖阳&#xff0c;很多中大型互联网公司扩大了未来一年的招聘需求。前不久&#xff0c;字节跳动放出了年末要招 1 万人的消息&#xff0c;腾讯校招规模也将扩张至 5000 人&…

Vue Router 4.0 正式发布!焕然一新。

关注若川视野&#xff0c;回复"pdf" 领取资料&#xff0c;回复"加群"&#xff0c;可加群长期交流学习12月8日&#xff0c;Vue Router 4 正式发布稳定版本。在经历了 14 个 Alpha&#xff0c;13 个 Beta 和 6 个 RC 版本之后&#xff0c;Vue Router v4 闪亮…

实战Nginx与PHP(FastCGI)的安装、配置与优化

转载链接&#xff1a;http://ixdba.blog.51cto.com/2895551/806622 一、什么是 FastCGI FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通信的接口。多数流行的HTTP server都支持FastCGI&#xff0c;包括Apache、Nginx和lighttpd等&#xff0c;同时&#xff0c;…

10个前端8个用Vue的,怎么才能在面试中出彩?

大家好&#xff0c;我是若川。现在但凡出去面试&#xff0c;面试官几乎必问 Vue3.0 。不仅会问一些核心特性&#xff0c;还会问原理层面的问题。比如&#xff1a;▶框架层面问题&#xff1a;Vue3.0 新特性 Composition API 与 React.js 中 Hooks 的异同点&#xff1f;▶源码、原…

故乡 | 登高望远,夜幕降临

欢迎星标我的公众号若川视野&#xff0c;回复加群&#xff0c;长期交流学习上周末看了几集豆瓣评分8.5分刘同同名小说的青春剧《我在未来等你》&#xff0c;让我回想起自己的高中生活。也想起小时候经常爬到故乡附近的小山&#xff0c;看夕阳西下。时常和同事开玩笑说&#xff…

CentOS5安装Nginx1.4+PHP5.5 FastCGI

转载链接&#xff1a;http://blog.csdn.net/staricqxyz/article/details/17012329 yum -y install gcc gcc-c autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2…

一份热乎乎的滴滴前端面经

关注若川视野&#xff0c;回复"pdf" 领取资料&#xff0c;回复"加群"&#xff0c;可加群长期交流学习滴滴前端实习面经滴滴是我投简历之后第二家面试的公司&#xff0c; 国庆节前两三天投的简历&#xff0c; 国庆后复工第一天就给我打了电话约一面。那时候…

用webBrowser取源文件取不到的点击数--选秀榜selectop.com网站内容管理系统之六

用idhttp可以取到源文件&#xff0c;但网站用脚本代码&#xff0c;源文件是看不到&#xff0c;并且代码的结果也取不出。webBrowser可以多次返回下载到的内容&#xff0c;不包括任何html语法&#xff0c;这个当中就有文章的点击数。在WebBrowser1DownloadComplete事件中处理&am…

真诚推荐几个最值得关注的前端公众号

前端技术日新月异&#xff0c;发展迅速&#xff0c;作为一个与时俱进的前端工程师&#xff0c;需要不断的学习。这里强烈推荐几个前端开发工程师必备的优质公众号&#xff0c;希望对你有所帮助。大家可以像我一样&#xff0c;利用碎片时间阅读这些公众号的文章。code秘密花园一…

Silverlight Unit Test Framework

微软在08年的时候推出了一个Silverlight的单元测试框架&#xff0c;该框架在Mix 08的时候与Silverlight controls同时推出的&#xff0c;微软工程师Jeff Wilcox一直参与维护该单元测试框架。Scott Gu对这个框架的介绍Jeff Wilcox提供的视频介绍该框架的源代码已经包括在Silverl…

Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解

转载链接&#xff1a;http://freeloda.blog.51cto.com/2033581/1288553 大纲 一、前言 二、环境准备 三、安装与配置Nginx 四、Nginx之反向代理 五、Nginx之负载均衡 六、Nginx之页面缓存 七、Nginx之URL重写 八、Nginx之读写分离 注&#xff0c;操作系统为 CentOS 6.4 x86_64…

能在任意一种框架中复用的组件,太牛了!

Web Component 是一种 W3C标准支持的组件化方案&#xff0c;通过它可以编写可复用的组件&#xff0c;同时也可以对自己的组件做更精细化的控制。更牛的是&#xff0c;Web Component 可以在任何一种框架中使用&#xff0c;不用加载任何模块、代码量小&#xff0c;优势非常明显&a…

stm32cubemx中文_用 STM32 通用定时器做微秒延时函数(STM32CubeMX版本)

概述​ 在使用 DHT11 的时候&#xff0c;时序通信需要微秒来操作&#xff0c;STM32CubeMX 自带一个系统时钟&#xff0c;但是实现的是毫秒级别的。因此就自己用通用计时器实现一个。文章目录环境&#xff1a;开发板&#xff1a;STM32F4探索者&#xff08;正点原子&#xff09;1…

人脸识别拷勤门禁主板_捷易讲解AI无感人脸识别考勤门禁终端设备在使用中的维护方法...

人脸识别考勤门禁终端设备虽然在出厂时&#xff0c;都有做密封处理&#xff0c;但面对细小的灰尘&#xff0c;并没有做到百分百防尘。灰尘对于AI无感人脸识别考勤门禁终端设备是有一定的影响的&#xff0c;他会沉淀在主板上、屏幕上&#xff0c;影响设备散热和正常工作&#xf…

【翻译】How-To: Using the N* Stack, part 3

原文地址&#xff1a;http://jasondentler.com/blog/2009/08/how-to-using-the-n-stack-part-3/ Java – 一种代码松散的XML 在我们学习 Fluent NHibernate 之前, 应该先了解下老式的 NHibernate 映射文件应该是怎样写的。 在一个典型的 NHibernate 配置中&#xff0c;你会有很…

你可能需要的网易前端三轮面经

关注若川视野, 回复"pdf" 领取资料&#xff0c;回复"加群"&#xff0c;可加群长期交流前言最近一个星期面了几家公司&#xff0c;最后收获了心仪的网易有道offer&#xff0c;于是推掉了其他的面试&#xff0c;至于一些其他大厂&#xff0c;并没有投简历&am…