Vue 3 学习 源码解读

 该文章内容为以下视频的学习笔记: 

 前言_哔哩哔哩_bilibili前言是秋招解决方案:深入 Vue3 源码,带你彻底打通 Vue3 源码面试的第1集视频,该合集共计13集,视频收藏或关注UP主,及时了解更多相关视频内容。icon-default.png?t=N7T8https://www.bilibili.com/video/BV1D8411B7Tx?p=1&vd_source=4298755c4e2edc1fe805c41cc2d7379a

 

1.Vue2 和 Vue3 的区别

  • 先明确改变的地方很多,并进行列举
  • 然后从两个重点问题中进行回答
  • 最后进行一个总结收尾

vue3 使用 TS 进行了完全的重构,改变的地方还是挺多的,比如:

  1. 新增的 Composition API(注意:vue3 也支持 Options API)

  2. 模块化的 API 调用(可以有效的进行 TreeShaking)

  3. 基于 Fragment 的多个根标签

  4. 响应式的实现原理

  5. diff 算法优化

  6. 生命周期的变化

  7. 新增的一些组件,比如:teleport、suspense 这些

  8. .....

主要两个比较核心的变化:

  1. 响应式实现原理的改变

  2. diff 算法优化的变化


(1)响应式原理:

在 vue2 中响应式核心还是通过 Object.defineProperty 进行实现的。通过 data 方法返回的对象作为 target。这样无论是 简单数据类型 还是 复杂数据类型 ,都可以直接通过  Object.defineProperty 监听 getter 和 setter 行为。

但是,由于  Object.defineProperty 只能监听指定对象、指定属性的响应性,所以 vue 需要对 data 中返回的复杂数据类型进行循环监听。

那么这样,当我们为响应式数据 动态新增属性(为对象新增一个之前不存在的属性,文档)时,会出现失去响应性的问题。

那么为了解决这个问题,vue2 增加了 Vue.set 的 API ,相当于主动触发了一次 Object.defineProperty。但是,这种方式其实并不方便,需要用户主动触发。

所以,vue3 中改用了 Proxy(也是因为浏览器逐渐升级,不再需要过分兼容旧的浏览器)。利用 Proxy 代理的特性解决了这个问题。


(2)diff 算法的优化:

Vue2 中的 diff 大家都喜欢把它叫做 双端 Diff 对比 。大致的思路是通过:新旧两组节点的四个端点(新节点组的开头、新节点组的结尾、旧节点组的开头、旧节点组的结尾) 进行对比,并试图找到可以复用的节点。

而 Vue3 中的 diff 大家都喜欢叫它做 快速 Diff

(注意:快速 diff 并不是官网声明的名字,只是国内都这么叫)。里面涉及到了  最长递增子序列 的概念,整体还是有点复杂的。

总体来说,Vue3 带来的变化很大。通过 Composition API,特别是 3.2 之后新增了 <script setup> 语法糖,让 vue 的使用更加接近了原生 js 实现。


2.Vue3 中的响应式实现原理

  • 先明确响应式的实现方式
  • 针对两种方案进行解析
  • 最后总结核心点 

Vue3 的响应式实现主要有两个部分:reactive、ref。

reactive 主要是通过 proxy 进行的响应式实现,核心是监听复杂数据类型的 getter 和 setter 行为。

当监听到 getter 行为的时候那么就收集当前的依赖行为,也就是 effect 。当触发 setter 行为的时候,那么就触发刚才收集的依赖。那么此时,所有获取到当前数据的地方都会更新执行,也就是完成了响应性。

但是 proxy 只能监听复杂数据类型,没有办法监听简单数据类型。所以 vue 专门提供了 ref 方法。ref 方法既可以处理简单数据类型、也可以处理复杂数据类型。它的实现在 3.2 之前和 3.2 之后是不同的。3,2 之前主要通过 Object.defineProperty 进行实现,在 3.2 版本的时候,根据社区贡献改为了  get value 和 set value 标记的方式进行实现。这也是为什么 ref 类型的数据必须要通过 .value 的方式使用的原因(本质上是触发 value 方法)。

当 ref 接收复杂数据类型的时候,会直接通过 toReactive 方法,把复杂数据类型交给 reactive 进行处理。

📜总结:整个的 vue3 响应性,主要就是由这两大块来进行实现的。proxy 处理复杂数据类型,get value 和 set value 处理简单数据类型。核心都是监听 setter 和 getter ,然后触发 effect 的方式。


3.computed 实现原理

  • 把 computed 与 ref 进行类比
  • 着重说调度器和脏处理
  • 总结核心内容

computed 和 ref 的实现是有一些类似的,比如:

  1. 它们本质上都是一个类(ComputedRefImpl)

  2. 都是通过 get value 和 set value 监听 getter 和 setter 行为的

但是因为 computed 的计算属性特性(依赖的响应式数据发生变化时,才会重新计算),所以在源码的实现上有一些区别,这个区别主要体现在两个地方:

  1. 调度器:scheduler

  2. 执行检查(脏状态):_dirty

1️⃣调度器 scheduler

它是作为 ReactiveEffect 的第二个参数存在的回调函数。当触发依赖的时候,会直接执行这个回调函数。

在这个回调函数中,会根据当前的脏值状态来决定是否需要触发依赖。

2️⃣ _dirty

它其实就是一个 boolean 的变量。

  • true:表示需要获取 计算之后 的最新数据

  • false:表示当前数据就是最新的,不需要重新计算

在每次去触发 get value (computed.value)的时候,都会根据这个 _dirty 的值来判断计算的触发。

📜总结:总的来说,计算属性的核心还是体现在 是否需要重新计算 这里。判断的方式就是通过 _dirty 进行的。而 scheduler 主要提供了函数的作用,在函数内部还是需要依赖 _dirty 来决定触发依赖的时机。


4.watch 实现原理

  • 说明 watch的处理逻辑
  • 着重说明依赖收集和触发、懒执行
  • 总结核心内容 

watch 是一个典型的懒执行 API,它的逻辑更加纯粹:在监听的响应式数据变化时,重新执行回调函数就可以了。核心的点有两个:

  1. 如何监听依赖 || 触发依赖的

  2. 如何进行懒执行的

1️⃣ watch 监听依赖 || 触发依赖的机制

watch 的监听和触发也是依赖的 setter 和 getter 行为。

这里的 setter 行为触发是比较明确的,本质上就是监听的响应式数据触发 setter 行为。

而 getter 行为的触发是依赖于内部的 traverse 方法进行的。traverse 方法就是 依次遍历数据,分别触发 getter 行为。

2️⃣懒执行本质上就是通过 options 中的 immediate 参数,逻辑比较简单。

因为 watch 内部通过 job 的方法来触发 callback(回调函数),如果 immediate 为 true 那么就主动触发一次 job 就可以了。

📜总结:

watch 的实现会更加纯粹一些。只需要关注好 setter 和 getter 以及 懒执行的特性即可。

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

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

相关文章

微信小程序——CSS3渐变

SS3 渐变&#xff08;gradients&#xff09;可以在两个或多个指定的颜色之间显示平稳的过渡。CSS3 定义了两种类型的渐变&#xff08;gradients&#xff09;&#xff1a; 说明 1、线性渐变&#xff08;Linear Gradients&#xff09;- 向下/向上/向左/向右/对角方向&#xff1…

Spring AOP 详解及@Trasactional

Spring AOP 详解 AOP基础 AOP: Aspect Oriented Program, 面向切面编程。解耦&#xff08;组织结构调整&#xff09;、增强&#xff08;扩展&#xff09;。 AOP术语 术语 说明 Aspect&#xff08;切面&#xff09; 横切于系统的连接点实现特定功能的类 JoinPoint&#xf…

编译工具链 之二 详解 ELF 格式及标准、UNIX 发展、ABI

在计算机及嵌入式系统中&#xff0c;二进制文件也有一定的标准格式&#xff0c;通常会包含在各平台的应用程序二进制接口 &#xff08;Application Binary Interface&#xff0c;ABI&#xff09;规范中。它是编译工具链必须要遵守的规范&#xff08;编译工具链产生符合 ABI 的二…

Qt单一应用实例判断

原本项目中使用QSharedMemory的方法来判断当前是否已存在运行的实例&#xff0c;但在MacOS上&#xff0c;当程序异常崩溃后&#xff0c;QSharedMemory没有被正常销毁&#xff0c;导致应用程序无法再次被打开。 对此&#xff0c;Qt assistant中有相关说明&#xff1a; 摘抄 qt-s…

tailscale自建headscale和derp中继

tailscale自建headscale和derp中继 Tailscale 官方的 DERP 中继服务器全部在境外&#xff0c;在国内的网络环境中不一定能稳定连接&#xff0c;所以有必要建立自己的 DERP 服务器的。 准备工作&#xff1a; 需要有自己的云服务器&#xff0c;本示例为阿里云轻量服务器需要有…

Spring的beanName生成器AnnotationBeanNameGenerator

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

11.3 读图举例

一、低频功率放大电路 图11.3.1所示为实用低频功率放大电路&#xff0c;最大输出功率为 7 W 7\,\textrm W 7W。其中 A \textrm A A 的型号为 LF356N&#xff0c; T 1 T_1 T1​ 和 T 3 T_3 T3​ 的型号为 2SC1815&#xff0c; T 4 T_4 T4​ 的型号为 2SD525&#xff0c; T 2…

(高阶) Redis 7 第21讲 IO多路复用模型 完结篇

🌹 以下分享 Redis IO多路复用模型,如有问题请指教。🌹🌹 如你对技术也感兴趣,欢迎交流。🌹🌹🌹 如有对阁下帮助,请👍点赞💖收藏🐱‍🏍分享😀 IO多路复用模型是什么 I/O:网络IO 多路:多个客户端连接(连接即套接字描述符,即socket或channel),指…

leetcode 49. 字母异位词分组

2023.10.7 根据字母异位词的定义&#xff0c;可知&#xff1a;所有字母异位词经过排序之后得到的字符串相同&#xff0c;所以可以定义一个哈希表&#xff0c;将排序后的字符串当作哈希表的键&#xff0c;哈希表的值则用来存储该字母异位词对应的所有字符串&#xff0c;最后将哈…

HDLbits: Shift18

先补充一下算术移位寄存器和按位移位寄存器&#xff1a; SystemVerilog具有按位和算术移位运算符。 按位移位只是将向量的位向右或向左移动指定的次数&#xff0c;移出向量的位丢失。移入的新位是零填充的。例如&#xff0c;操作8’b11000101 << 2将产生值8’b00010100…

【数据结构-二叉树 八】【遍历求和】:求根到叶子节点数字之和

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【遍历求和】&#xff0c;使用【二叉树】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&am…

练[SUCTF 2019]CheckIn

[SUCTF 2019]CheckIn 文章目录 [SUCTF 2019]CheckIn掌握知识解题思路关键paylaod 掌握知识 ​ .user.ini文件上传利用–需要上传目录有一个php文件(index.php)&#xff0c;文件头绕过&#xff0c;文件内容<&#xff1f;检测 解题思路 打开题目链接&#xff0c;发现又是一…

[SWPUCTF 2021 新生赛]easy_sql - 联合注入||报错注入||sqlmap

[SWPUCTF 2021 新生赛]easy_sql 一、思路分析二、解题方法解法一&#xff1a;手注解法二&#xff1a;报错注入解法三&#xff1a;sqlmap 一、思路分析 这题可以直接参考&#xff1a;[NISACTF 2022]join-us - 报错注入&无列名注入 网站标题提示&#xff0c;参数是wllm ?…

day25--JS进阶(递归函数,深浅拷贝,异常处理,改变this指向,防抖及节流)

目录 浅拷贝 1.拷贝对象①Object.assgin() ②展开运算符newObj {...obj}拷贝对象 2.拷贝数组 ①Array.prototype.concat() ② newArr [...arr] 深拷贝 1.通过递归实现深拷贝 2.lodash/cloneDeep实现 3.通过JSON.stringify()实现 异常处理 throw抛异常 try/catch捕获…

Linux TCP协议通信 (流程 三次握手 四次挥手 滑动窗口)

TCP通信流程 Socket函数 TCP通信实现&#xff08;服务器端&#xff09; #include <stdio.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> int main() {//1.创建socketint lfd socket(AF_INET, SOCK_…

kafka的请求处理机制

目录 前言&#xff1a; kafak是如何处理请求的&#xff1f; 控制请求与数据类请求 参考资料 前言&#xff1a; 无论是 Kafka 客户端还是 Broker 端&#xff0c;它们之间的交互都是通过“请求 / 响应”的方式完成的。比如&#xff0c;客户端会通过网络发送消息生产请求给 B…

四位十进制频率计VHDL,DE1开发板验证,仿真和源码

名称&#xff1a;四位十进制频率计VHDL&#xff0c;DE1开发板验证 软件&#xff1a;Quartus 语言&#xff1a;VHDL 要求&#xff1a; 数字频率计设计要求 1、四位十进制数字显示的数学式频率计,其频率测量范围为10~9999khz,测量单位为kHz。 2、要求量程能够转换。即测几十…

蓝桥杯每日一题2023.10.8

题目描述 七段码 - 蓝桥云课 (lanqiao.cn) 题目分析 所有的情况我们可以分析出来一共有2的7次方-1种&#xff0c;因为每一个二极管都有选择和不选择两种情况&#xff0c;有7个二极管&#xff0c;但是还有一种都不选的情况需要排除&#xff0c;故-1 枚举每个方案看是否符合要…

【图像处理】【应用程序设计】加载,编辑和保存图像数据、图像分割、色度键控研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

MongoDB数据库网站网页实例-编程语言Python+Django

程序示例精选 PythonDjangoMongoDB数据库网站网页实例 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonDjangoMongoDB数据库网站网页实例》编写代码&#xff0c;代码整洁&#xff0c;…