专栏分享:vue2源码专栏vue3源码专栏vue router源码专栏玩具项目专栏,硬核推荐

欢迎各位ITer关注点赞收藏

背景

以下是柏成根据Vue3官方课程整理的响应式书面文档 - 第一节,课程链接在此:Vue 3 Reactivity - Vue 3 Reactivity | Vue Mastery,本文档可作为课程的辅助材料,配合食用,快乐双倍!

我们先来看一下这个简单的Vue应用程序,Ok!如果我们加载了这个组件,然后我们的价格price发生了改变,Vue是如何知道更新模版内容的呢?接下来,我们将会用 Vue3 建造响应式的方法,从头开始制造一个响应式引擎,让我们一步一步的来解决这个问题!

dep

How can we save the total calculation, so we can run it agine when price or quantity updates ?

如何存储 total 的计算方式,当 price 或 quantities 更新时,total 再计算一次?

我们想将下面这段代码存储在某种储藏室中,然后我们需要运行它,之后我们还想再次运行这个被存储的代码【被存储可能有多种功能代码】

let total = price * quantity

让我们来实现一下,下面所列举的effect()track()trigger()你都可以在 Vue3 响应性源码中看到同名的函数。

  • dep:一个 Set 对象,存储我们的effects,或者说是一个effect集(Set)。我们在这里使用 Set 的原因是 Set 不允许出现重复值,当我们尝试添加同样的effect时,它不会变成 Set 集合的两个子成员
  • effect():一个方法,包含了我们想要存储的代码
  • track():一个方法,使用dep变量去保存effect
  • trigger():一个方法,遍历dep去运行我们存储的所有代码

depsMap

Often our objects will have multiple properties and each property will need their own dep. How can we store these ?

通常,我们的对象会有多个属性,每个属性都需要自己的 Dep(依赖关系),或者说 effect 的 Set 集合,那么,我们如何存储,或者说怎样才能让每个属性都拥有自己的依赖呢?

我们现在拥有一个product对象,其每一个属性都需要有自己的dep。【dep其实就是一个effect集(Set),这个 effect集应该在值发生改变时重新运行。】

正如我们看到的,dep的类型是 Set,Set 中的每个值都只是一个我们需要执行的effect,就像我们这个计算total的匿名函数。要把这些dep存储起来,且方便我们以后在找到他们,我们要创建一个depsMap

  • depsMap: 一个 Map 对象,存储了每个属性到其自己依赖dep对象的映射;每一个属性都拥有它们自己的,可以重新运行effectdep;我们使用对象属性名作为键,比如pricequantity,值是一个depeffect集】

让我们来实现一下,代码如下:

<html>
<head></head>
<body>
<div id="app">
<div>depsMap</div>
</div>
</body>
<script>
const depsMap = new Map() // Save this code
function track(key) {
let dep = depsMap.get(key) // Get the dep for this property
if (!dep) {
depsMap.set(key, (dep = new Set())) // No dep yet, so let's create one
}
dep.add(effect) // Add this effect Since it's a set, it won't add the effect again if it already exists
} // Run all the code I've saved
function trigger(key) {
let dep = depsMap.get(key) // Get the dep for the key
if (dep) {
dep.forEach(effect => {
effect() // If it exists, run each effect
})
}
} let product = {
price: 5,
quantity: 2,
}
let total = 0 let effect = () => {
total = product.price * product.quantity
} track('quantity')
effect()
</script>
</html>

当我们触发函数trigger('quantity')effect就运行了;控制台输出结果如下:

现在我们就对 对象中的不同属性 有了一种跟踪依赖关系的方法

targetMap

What if we have multiple reactive objects that each need to track effects ?

如果我们有多个响应式对象,每个响应式对象属性都需要存储 effect 呢?例如?

let product = { price: 5, quantity: 2 }
let user = { name: "burc", age: 18 }

到目前为止,我们有一张 depsMap,它存储了每个属性自己的依赖对象(属性到自己依赖对象的映射)。然后每个属性都拥有它们自己的并可以重新运行effectdep

我们这里需要一个其他对象,即 targetMap 。它的键以某种方式引用了我们的响应性对象,例如productuser

  • targetMap: 一个 WeakMap 对象,它储存了与每个 响应性对象属性 关联的依赖,在 Vue3 中,它被称为目标图
  • WeakMap: 与 Map 结构类似,但只接受对象作为键名(null除外),不接受其他类型的值作为键名

用一个简单的例子告诉我们 WeakMap 是如何工作的,如想了解详细API请移步 阮一峰ES6文档-WeakMap

let product = { price: 5, quantity: 2 }

const targetMap = new WeakMap()
targetMap.set(product, "example code to test") console.log(targetMap.get(product))
//"example code to test"

让我们来实现一下,代码如下:

<html>
<head></head>
<body>
<div id="app">
<div>targetMap</div>
</div>
</body>
<script>
const targetMap = new WeakMap() // For storing the dependencies for each reactive object // Save this code
function track(target, key) {
let depsMap = targetMap.get(target) // Get the current depsMap for this target(reactive object - product)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map())) // If it doesn't exist, create it
}
let dep = depsMap.get(key) // Get the dependency object for this peoperty - quantity
if (!dep) {
depsMap.set(key, (dep = new Set())) // If it doesn't exist, create it
}
dep.add(effect) // Add the effect to the dependency
} // Run all the code I've saved
function trigger(target, key) {
const depsMap = targetMap.get(target) // Does this object have any properties that have dependencies?
if (!depsMap) {
return // If no, return from the function immediately
}
let dep = depsMap.get(key) // Otherwise, check if this property has a dependency
if (dep) {
dep.forEach(effect => {
effect()
}) // Run those
}
} let product = { price: 5, quantity: 2 }
let total = 0 let effect = () => {
total = product.price * product.quantity
} track(product, 'quantity')
effect()
</script>
</html>

当我们触发函数 trigger(product, 'quantity')effect就运行了;控制台输出结果如下:

diagram

让我们再分析概括一下图表

  • targetMap:存储了每个 响应性对象属性 关联的依赖;类型是 WeakMap
  • depsMap:存储了每个属性的依赖;类型是 Map
  • dep:存储了我们的effects,一个effects集,这些effect在值发生变化时重新运行;类型是 Set

Now!我们就实现了一种储存不同effect的方法,但是我们还没有办法让我们的effect自动重新运行。这是第二个重要的部分,将在下一篇文章讲解!

【Vue3响应式入门#01】Reactivity的更多相关文章

  1. vue3响应式原理以及ref和reactive区别还有vue2/3生命周期的对比,第二天

    前言: 前天我们学了 ref 和 reactive ,提到了响应式数据和 Proxy ,那我们今天就来了解一下,vue3 的响应式 在了解之前,先复习一下之前 vue2 的响应式原理 vue2 的响应 ...

  2. 由浅入深,带你用JavaScript实现响应式原理(Vue2、Vue3响应式原理)

    由浅入深,带你用JavaScript实现响应式原理 前言 为什么前端框架Vue能够做到响应式?当依赖数据发生变化时,会对页面进行自动更新,其原理还是在于对响应式数据的获取和设置进行了监听,一旦监听到数 ...

  3. vue3响应式模式设计原理

    vue3响应式模式设计原理 为什么要关系vue3的设计原理?了解vue3构建原理,将有助于开发者更快速上手Vue3:同时可以提高Vue调试技能,可以快速定位错误 1.vue3对比vue2 vue2的原 ...

  4. 第三十六篇:vue3响应式(关于Proxy代理对象,Reflect反射对象)

    好家伙,这个有点难. 1.代理对象Proxy Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找.赋值.枚举.函数调用等). 拦截对象中任意属性的变化,包括:查get, ...

  5. Vue3响应式系统api 之 ref reactive

    reactive 接收一个普通对象然后返回该普调对象的响应式代理.等同于2.x的  Vue.observable() Vue3中响应数据核心是 reactive , reactive 中的实现是由 P ...

  6. vue2响应式原理与vue3响应式原理对比

    VUE2.0 核心 对象:通过Object.defineProtytype()对对象的已有属性值的读取和修改进行劫持 数组:通过重写数组更新数组一系列更新元素的方法来实现元素的修改的劫持 Object ...

  7. vue3 第二天vue响应式原理以及ref和reactive区别

    前言: 前天我们学了 ref 和 reactive ,提到了响应式数据和 Proxy ,那我们今天就来了解一下,vue3 的响应式 在了解之前,先复习一下之前 vue2 的响应式原理 vue2 的响应 ...

  8. 前端必读:Vue响应式系统大PK

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://www.sitepoint.com/vue-3-reactivity-system ...

  9. 前端必读:Vue响应式系统大PK(下)

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://www.sitepoint.com/vue-3-reactivity-system ...

  10. 【01】《响应式Web设计:HTML5和CSS3实战》

    [01]   (魔芋:已看完.) [01]<响应式Web设计:HTML5和CSS3实战>(全).pdf 共246页.   2013年1月出版.   读后感:适合入门的书籍,对于响应式布局, ...

随机推荐

  1. Kubernetes(k8s) 资源限制:resources,LimitRange,ResourceQuota

    目录 一.系统环境 二.前言 三.Kubernetes资源限制简介 四.创建没有资源限制的pod 4.1 创建没有资源限制的pod 4.2 内存消耗测试 五.使用resources字段配置资源限制 5 ...

  2. LRU 力扣 146 https://leetcode.cn/problems/lru-cache/

    一道经典题目,用双向链表去做能够满足O1的复杂度 核心代码如下 class LRUCache {    MyLinkedList myLinkedList;    int size;    int c ...

  3. 【Java 新的选择】,Solon v2.3.8 发布

    Solon 是什么开源项目? 一个,Java 新的生态型应用开发框架.它从零开始构建,有自己的标准规范与开放生态(历时五年,已有全球第二级别的生态规模).与其他框架相比,它解决了两个重要的痛点:启动慢 ...

  4. HTTP&HTTPS协议

    HTTP协议 1.什么是HTTP 超文本传输协议( HyperText Transfer Protoco,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议. HTTP(HyperT ...

  5. 学习LVM:archive 和 backup目录

    推荐文档:Logical Volume Manager Administration 在掌握了基本的commands操作后,你是否对操作背后的一些东西产生好奇呢? 程序的configure一般会提供这 ...

  6. vulnhub billu:b0x

    知识点 SQLi.目录爆破.数据库操作.文件包含漏洞.提权.反弹shell 解题步骤 nmap扫描有80,22端口 nmap -sV -Pn -T 4 192.168.220.132 访问网页提示sq ...

  7. 文心一言 VS 讯飞星火 VS chatgpt (68)-- 算法导论6.5 7题

    文心一言 VS 讯飞星火 VS chatgpt (68)-- 算法导论6.5 7题 七.试说明如何使用优先队列来实现一个先进先出队列,以及如何使用优先队列来实现栈(队列和栈的定义见 10.1 节.) ...

  8. http头部字段Origin和Access-Control-Allow-Origin解决请求跨域

    Http协议中请求头和响应头携带了很多信息,其中 请求头 Origin,响应头 Access-Control-Allow-Origin 与跨域有关. 为了验证跨域,要将客户端和服务端分配在不同端口,这 ...

  9. 操作系统实验——利用Linux的消息队列通信机制实现两个线程间的通信

    目录 一. 题目描述 二.实验思路 三.代码及实验结果 四.遇到问题及解决方法 五.参考文献 一. 题目描述 编写程序创建三个线程:sender1线程.sender2线程和receive线程,三个线程 ...

  10. GitHub Actions CI/CD 工作流实战

    1. 什么是 GitHub Actions 与 workflow ? GitHub Actions 是 GitHub 提供的一种持续集成(CI)和持续部署(CD)的工具,用于自动化软件开发过程中的各种 ...