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.hqwc.cn/news/128064.html

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

相关文章

JVM上篇之虚拟机与java虚拟机介绍

目录 虚拟机 java虚拟机 简介 特点 作用 位置 整体结构 类装载子系统 运行时数据区 java执行引擎 Java代码执行流程 jvm架构模型 基于栈式架构 基于寄存器架构 总结 jvm的生命周期 1.启动 2.执行 3.退出 JVM的发展历程 虚拟机 所谓虚拟机&#xff0c;指的…

【微服务】RedisSearch 使用详解

目录 一、RedisJson介绍 1.1 RedisJson是什么 1.2 RedisJson特点 1.3 RedisJson使用场景 1.3.1 数据结构化存储 1.3.2 实时数据分析 1.3.3 事件存储和分析 1.3.4 文档存储和检索 二、当前使用中的问题 2.1 刚性数据库模式限制了敏捷性 2.2 基于磁盘的文档存储导致瓶…

数字三角形加强版题解(组合计数+快速幂+逆元)

Description 一个无限行的数字三角形&#xff0c;第 i 行有 i 个数。第一行的第一个数是 1 &#xff0c;其他的数满足如下关系&#xff1a;如果用 F[i][j] 表示第 i 行的第 j 个数&#xff0c;那么 F[i][j]A∗F[i−1][j]B∗F[i−1][j−1] &#xff08;不合法的下标的数为 0 &a…

Springboot项目log4j与logback的Jar包冲突问题

异常信息关键词&#xff1a; SLF4J: Class path contains multiple SLF4J bindings. ERROR in ch.qos.logback.core.joran.spi.Interpreter24:14 - no applicable action for [properties], current ElementPath is [[configuration][properties]] 详细异常信息&#xff1a…

水波纹文字效果动画

效果展示 CSS 知识点 text-shadow 属性绘制立体文字clip-path 属性来绘制水波纹 工具网站 CSS clip-path maker 效果编辑器 页面整体结构实现 使用多个 H2 标签来实现水波纹的效果实现&#xff0c;然后使用clip-path结合动画属性一起来进行波浪的起伏动画实现。 <div …

盒子模型的基础

盒子模型 边框&#xff08;border&#xff09; border可以设置元素的边框&#xff0c;边框分成三部分&#xff0c;边框的&#xff08;粗细&#xff09;边框的样式&#xff0c;边框的颜色 <style>div {width: 100px;height: 100px;border-width: 200;border-style: 边框…

应用层协议——DNS、DHCP、HTTP、FTP

目录 1、DNS 协议 1-1&#xff09;Hosts 文件 1-2&#xff09;DNS 系统 1-3&#xff09;域名的组成、分类和树状结构 1-4&#xff09;DNS 域名服务器类型 1-5&#xff09;DNS 查询方式 1-6&#xff09;DNS 域名解析的一般步骤 1-7&#xff09;对象类型与资源记录 2、D…

ELK整合springboot(第二课)

一、创建一个springboot的项目 pom文件如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLo…

深入解析 const 关键字:指针、参数、返回值和类成员函数

文章目录 const 关键字的理解一、 修饰普通类型的变量二、const 修饰指针变量三、const 作参数传递 和 函数返回值&#xff08;1&#xff09;const 修饰函数参数&#xff08;2&#xff09;const 修饰函数返回值 四、const修饰类成员函数结尾 const 关键字的理解 const 在 C 中…

基于SVM+TensorFlow+Django的酒店评论打分智能推荐系统——机器学习算法应用(含python工程源码)+数据集+模型(一)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境TensorFlow 环境方法一方法二 安装其他模块安装MySQL 数据库 模块实现1. 数据预处理1&#xff09;数据整合2&#xff09;文本清洗3&#xff09;文本分词 相关其它博客工程源代码下载其它资料下载 前言 本项目以支…

好物周刊#19:开源指北

https://github.com/cunyu1943/JavaPark https://yuque.com/cunyu1943 村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. Vditor 一款浏览器端的 Markdown 编辑器&#xff0c;支持所见即所得、…

三十一、【进阶】B+树的演变过程

1、B树简单介绍 &#xff08;1&#xff09;介绍&#xff1a;B树也属于B树&#xff0c;是B树的变种 &#xff08;2&#xff09;特点&#xff1a;所有的数据都位于叶子节点上&#xff0c;叶子节点上的所有元素形成了一个单项链表 &#xff08;3&#xff09;图示&#xff1a; 2…