当前位置: 首页 > news >正文

Vue2 - 数据响应式原理

目录

  • 1,总览
  • 2,Observer
  • 3,Dep
  • 4,Watcher
  • 5,Schedule

1,总览

vue2官网参考

在这里插入图片描述
简单介绍下上图流程:以 Data 为中心来说,

  1. Vue 会将传递给 Vue 实例的 data 选项(普通 js 对象),通过 Object.defineProperty 把这些 property 全部转为 getter/setter
  2. 当执行 render 函数时,会触发用到的响应式数据的 gettergetter 会进行依赖收集并放到 Watcher 中。
  3. 当修改被收集到 Watcher 中的响应式数据时,会触发 settersetter 会通知 Watcher 来重新执行 render 函数更新DOM树,同时再次进行第2步,形成闭环重复整个流程。

template 模板最终也会被编译为 render 函数执行。参考虚拟DOM树生成流程

响应式数据的目标:当对象本身或是属性发生变化时,会运行一些函数(最常见的是 render 函数)。

具体实现,vue 用到了几个核心部件。

  • Observer
  • Dep
  • Watcher
  • Schedule

2,Observer

目标:将传递给 Vue 实例的 data 选项(普通 js 对象)转化为响应式对象。

为了实现这点,Observer 把对象的每个属性通过 Object.defineProperty 转换为带有 getter/setter 的属性。这样当访问或修改这些属性时,vue 就可以做一些事情了。

在这里插入图片描述
Observer 是 Vue 内部的构造器,可以通过 Vue 提供的静态方法 Vue.observable(object) 间接使用该功能。

Vue.observable(object) 的使用场景参考这篇文章。

时间点:发生在 beforeCreate 之后,created之前。

具体实现:递归遍历所有属性,以完成深度的属性转换。

而由于只能遍历已有的属性,所以无法监测到将来动态添加或删除的属性。因为提供了 $set$delete 这2个实例方法。

对于数组,为了监听那些可能改变数组内容的方法,vue 更改了数组的隐式原型

vue 处理过后的数组 this.arr.__proto__上有7个方法可以被监听到。同时 this.arr.__proto__.__proto__ 指向真正的数组原型来正常使用数组的其他方法。
在这里插入图片描述

注意,直接修改数组的元素,是无法触发更新的。比如this.arr[0] = 1。但是修改数组中某一个元素对象的属性时,是可以监听到的。比如 this.arr[0].name = 'xxx'

总之,Observer 就是为了让一个对象属性的读取和赋值,内部数组变化等都可以被感知到。

3,Dep

作用和原理:

Vue会为响应式对象中的每个属性、对象本身、数组本身创建一个 Dep 实例(一个列表),每个 Dep 实例都可以做两件事:

  • 记录(收集)依赖:当读取响应式对象的某个属性时,它会进行依赖收集。
  • 派发更新:当改变某个属性时,它会派发更新。
function defineReactive(obj, key, val) {let Dep; // 依赖Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: () => {// 被读取了,将这个依赖收集起来Dep.depend();return val;},set: (newVal) => {if (val === newVal) {return;}val = newVal;// 被改变了,派发更新Dep.notify();},});
}

在这里插入图片描述
举例:

<!-- 组件 -->
<template><div><div>{{ obj.a }}</div><div>{{ arr }}</div><button @click="count++">修改conut</button></div>
</template><script>
// 会创建的 Dep 的元素:
export default {data() {return {obj: { // Depa: 1, // Depb: 2},arr: [1, 23, 4], // Depcount: 0};},
};
</script>
  • 因为模板中使用了 obj.a,所以 obj 自身和 a 属性都会创建 Dep
  • count 不会创建,是因为count其实并没有在模板中使用,而事件在渲染时不会运行。

有个问题,为什么要给对象自身也创建个 Dep,直接给用到的属性创建不可以吗?

不可以,因为直接修改对象(this.obj = xxx),或通过 this.$set(this.obj,"c", 3)this.$set(this.obj,"a") 增删属性时,都需要直接修改对象自身,才能完成响应式更新。

所以,最好一开始就定义好对象属性的初始值,来避免使用 this.$setthis.$delete 来触发对象自身的 Dep
因为使用 this.obj.a 直接触发属性 aDep 效率会更好。

对一个属性来说,会收集依赖的有3个可能的位置(因为都需要响应式更新或执行):

  • 模板,也就是 render() 中。
  • this.$watch() 中。
  • computed() 中。

4,Watcher

新的问题:Dep 是如何知道谁在用我的?换句话说,是谁触发的 getter 后执行的 Dep.depend()

比如,某个函数执行时用到了响应式数据 aa 怎么知道是哪个函数用的自己?

Vue的解决方式:Vue 不会直接执行函数,而是把函数交给一个叫 Watcher(一个对象)去执行。每个用到响应式数据的函数执行时,都会创建一个 Watcher,通过它来执行函数。
之后响应式数据变化时,Dep 会通知对应的 Watcher,去运行对应的函数来触发更新。

在这里插入图片描述

Watcher 大致原理

首先有一个全局变量。

  1. 在执行给它的函数之前,将它的 this 赋值给这个全局变量。
  2. 执行函数时,会触发响应式数据的 getter 后执行的 Dep.depend()
  3. Dep.depend() 的逻辑中,会检查这个全局变量,从而确定是哪个 Watcher
  4. 函数执行完后清空全局变量。

所以,对于一个组件实例来说,都至少对应一个 Watcher ,它记录的是该组件的 render 函数。
Watcher 首先会运行一次 render 来收集依赖,于是 render 函数中用到的响应式数据都会记录这个 Watcher
之后响应式数据变化,Dep 会通知这个 Watcher 来运行 render 函数触发更新,重新渲染页面同时再次收集当前的依赖。

打印组件的 this

在这里插入图片描述

Watcher 触发更新时,会进行对比新旧虚拟DOM树,完成对真实DOM的更新。具体原理参考diff 的原理

5,Schedule

新的问题又出现了,假如 render 函数中使用的响应式数据有多个 abcd,那这些数据都会记录 Watcher,之后一次性修改这4个时,render 函数就会执行4次,效率岂不是很低。

实际上,Watcher 在收到派发更新的通知后,不是立即执行对应的函数,而是把自己交给一个叫Schedule(调度器)的东西。

调度器维护一个队列,相同的 Watcher 仅会存在一次(类似 Set)。这些 Watcher 也不是立即执行,而是把需要执行的 Watcher 放到事件循环的微队列中(通过工具方法 nextTick )。

所以当响应式数据发生变化时,执行的 render 函数是异步的。


整体流程:

在这里插入图片描述


以上。

相关文章:

Vue2 - 数据响应式原理

目录 1&#xff0c;总览2&#xff0c;Observer3&#xff0c;Dep4&#xff0c;Watcher5&#xff0c;Schedule 1&#xff0c;总览 vue2官网参考 简单介绍下上图流程&#xff1a;以 Data 为中心来说&#xff0c; Vue 会将传递给 Vue 实例的 data 选项&#xff08;普通 js 对象&a…...

基于华为云解析服务实现网站区域封禁

前言 中国大陆以外的网络攻击不断&#xff0c;个人博客时常遭受不明个人或组织的攻击&#xff0c;给网站的安全运行带来了巨大的风险&#xff0c;同时DDoS、CC攻击等还会消耗服务器的资源&#xff0c;站长可能需要因此支付高昂的服务器、CDN的流量费用。 因此&#xff0c;如果…...

在 Docker 中配置 MySQL 数据库并初始化 Project 项目

1. 文件准备 1.1. 添加 SQL 文件头部内容 每个 SQL 文件的头部需要添加以下内容&#xff1a; DROP DATABASE IF EXISTS xx_..; CREATE DATABASE xx_..; USE xx_..;1.2. 修改 AUTO_INCREMENT 在每个 SQL 文件中&#xff0c;将 AUTO_INCREMENT 修改为 1。 1.3. 插入机型 在 SQL…...

生活中的物理3——神奇陷阱(随机倒下的抽屉柜门)

1实验 材料&#xff1a;大自然&#xff08;风&#xff09;、抽屉门松掉的抽屉 实验 1、找一个大风的日子&#xff0c;打开窗户&#xff08;不要找下雨天&#xff0c;不然你会被你亲爱的嫲嫲KO&#xff09; 2、让风在抽屉面前刮过 3、你发现了什么&#xff1f;&#xff1f;&…...

数模学习day08-拟合算法

这里拟合算法可以和差值算法对比 引入 插值和拟合的区别 与插值问题不同&#xff0c;在拟合问题中不需要曲线一定经过给定的点。拟 合问题的目标是寻求一个函数&#xff08;曲线&#xff09;&#xff0c;使得该曲线在某种准则下与所 有的数据点最为接近&#xff0c;即曲线拟…...

第13课 利用openCV检测物体是否运动了

FFmpeg与openCV绝对是绝配。前面我们已经基本熟悉了FFmpeg的工作流程&#xff0c;这一章我们重点来看看openCV。 在前面&#xff0c;我们已经使用openCV打开过摄像头并在MFC中显示图像&#xff0c;但openCV能做的要远超你的想像&#xff0c;比如可以用它来实现人脸检测、车牌识…...

C#之反编译之路(一)

本文将介绍微软反编译神器dnSpy的使用方法 c#反编译之路(一) dnSpy.exe区分64位和32位,所以32位的程序,就用32位的反编译工具打开,64位的程序,就用64位的反编译工具打开(个人觉得32位的程序偏多,如果不知道是32位还是64位,就先用32位的打开试试) 目前只接触到wpf和winform的桌…...

使用CentOS 7.6搭建HTTP隧道代理服务器

在现代网络环境中&#xff0c;HTTP隧道代理服务器因其灵活性和安全性而受到广泛关注。CentOS 7.6&#xff0c;作为一个稳定且功能强大的Linux发行版&#xff0c;为搭建此类服务器提供了坚实的基础。 首先&#xff0c;我们需要明确HTTP隧道代理的基本原理。HTTP隧道代理允许客户…...

Swift爬虫使用代理IP采集唯品会商品详情

目录 一、准备工作 二、代理IP的选择与使用 三、使用Swift编写唯品会商品爬虫 四、数据解析与处理 五、注意事项与优化建议 六、总结 一、准备工作 在开始编写爬虫之前&#xff0c;需要准备一些工具和库&#xff0c;以确保数据抓取的顺利进行。以下是所需的工具和库&…...

高性价比LDR6028Type-C转3.5mm音频和PD快充转接器

随着市面上的大部分手机逐渐取消了3.5mm音频耳机接口&#xff0c;仅保留一个Type-C接口&#xff0c;追求音质和零延迟的用户面临着一大痛点。对于这些用户&#xff0c;Type-C转3.5mm接口线的出现无疑是一大福音。这款线材在刚推出时就受到了手机配件市场的热烈欢迎&#xff0c;…...

【Docker】docker 服务相关命令

目录 1. 启动docker 服务 2.查看docker 服务的状态 3. 停止docker 服务 4.重启 docker 服务 5.开机自启动命令 1. 启动docker 服务 systemctl start docker 2.查看docker 服务的状态 systemctl status docker 3. 停止docker 服务 systemctl stop docker 此时再使用 syst…...

基于SpringBoot的在线问卷调查系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的在线问卷调查系统,java…...

智能分析网关V4太阳能风光互补远程视频智能监控方案

一、背景需求 在一些偏远地区&#xff0c;也具有视频监控的需求。但是这类场景中&#xff0c;一般无法就近获取市电&#xff0c;如果要长距离拉取市电&#xff0c;建设的成本非常高且长距离传输有安全隐患&#xff0c;因此风光互补远程视频监控方案的需求也较多。利用风光电转化…...

250:vue+openlayers 加载geotiff文件,并在地图上显示

第250个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+openlayers中加载geotiff文件,并在地图上显示。这里使用到了WebGLTile图层和GeoTIFF脚本模块。这里一定要注意GeoTIFF的数据加载方式,要数组的模式。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现…...

【JavaEE】多线程(7) -- 线程池的概念和简单实现

目录 1.线程池是什么 2.标准库中的线程池 2.1ThreadPoolExecutor 2.2构造方法参数介绍 2.3拒绝策略(面试易考) 2.4Executor的使用 3.实现线程池 1.线程池是什么 线程池是一种用来管理线程的机制&#xff0c;它可以有效地控制线程的创建、复用和销毁&#xff0c;从而提高程…...

集合基础知识点

集合基础 1. 集合的由来 当 Java 程序中需要存放数据的时候&#xff0c;通常会定义变量来实现数据的存储&#xff0c;但是&#xff0c;当需要存储大量数据的时候该怎么办呢&#xff1f;这时首先想到的是数组&#xff0c;但是&#xff01;数组只能存放同一类型的数据&#xff…...

最新版付费进群系统源码 /同城定位付费进群源码 /自带定位完整版/后台分销站点

源码介绍&#xff1a; 最新版付费进群系统源码 &#xff0c;它是同城定位付费进群源码&#xff0c;而且自带定位完整版和后台分销站点。 看到有些人分享一些虚假的内容或者缺少文件的内容。现在分享完整给大家&#xff0c;功能是完整的。它是同城定位付费进群源码。 功能&am…...

【论文阅读笔记】医学多模态新数据集-Large-scale Long-tailed Disease Diagnosis on Radiology Images

这是复旦大学2023.12.28开放出来的数据集和论文&#xff0c;感觉很宝藏&#xff0c;稍微将阅读过程记录一下。 Zheng Q, Zhao W, Wu C, et al. Large-scale Long-tailed Disease Diagnosis on Radiology Images[J]. arXiv preprint arXiv:2312.16151, 2023. 项目主页&#xf…...

(C语言)指针的进阶

1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2.指针的大小是固定的4/8个字节(32位平台/64位平台)。 3.指针是有类型&#xff0c;指针的类型决定了指针的-整数的步长&#xff0c;指针解引用操作的时候的权限。 4.指针的运算。 一、关于两…...

【网络面试(5)】收发数据及断开服务器(四次挥手)

前面了解到服务器和客户端在创建套接字&#xff0c;建立连接后&#xff0c;就可以进入到下一步&#xff0c;双发可以互相发送和接收数据&#xff0c;本篇博客就来学习一下这个过程。  我们印象里&#xff0c;发送数据应该是我们在浏览器输入网址&#xff0c;敲击回车的一瞬间&…...

【Maven】下载及配置

文章目录 1. 定义2. 下载3. 解压4. 配置环境变量5. 验证6. 特性 1. 定义 Maven 是一个跨平台的项目管理工具。作为 Apache 组织的一个颇为成功的开源项目&#xff0c;其主要服务于基于 Java 平台的项目创建&#xff0c;依赖管理和项目信息管理&#xff0c;是一个自动化构建工具…...

【方法】PPT设置密码后如何修改?

PowerPoint是我们日常和工作中经常用到的办公软件&#xff0c;有时候为了保护文件&#xff0c;还会设置密码&#xff0c;那设置密码后又想要修改密码&#xff0c;怎么操作呢&#xff1f;下面来看看PPT常用的两种密码是如何修改的。 1. “打开密码” 想要修改PPT的“打开密码”…...

第34期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…...

2023新版edge浏览器页面加载不出来的解决办法

2023新版edge浏览器页面加载不出来的原因有很多&#xff0c;以下是一些可能的解决方法&#xff1a; - 检查网络连接&#xff1a;确保你的设备连接到稳定的网络&#xff0c;尝试重新启动路由器或调制解调器。 - 清除浏览器缓存&#xff1a;打开edge浏览器&#xff0c;点击右上…...

算法基础之二分与前缀和 day 6

文章目录 二分第一类第二类 前缀和原题链接题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 题目分析示例代码 二分 二分法是我们在高中数学就学习过的一种思想&#xff0c;他也是一种效率较高的查找算法&#xff0c;在编写代码的过程中&#xff0…...

github短视频去除水印项目Douyin_TikTok_Download_API介绍

当下正值短视频盛行的时代。在我们浏览短视频的同时&#xff0c;经常能发现一些精美的图片、引人入胜的文案以及吸引眼球的视频&#xff0c;想要将它们保存到本地。然而&#xff0c;保存下来的图片或视频通常伴随着不太愉悦的水印&#xff0c;这显著降低了使用体验。因此&#…...

FindMy技术用于键盘

键盘是我们生活中不可或缺的输入工具&#xff0c;是人与计算机之间沟通的桥梁&#xff0c;无论是编写文档、浏览网页、玩游戏、或是进行复杂的数据分析&#xff0c;键盘都在其中发挥着关键的作用。此外&#xff0c;键盘还是各种软件的快捷键操作的关键。通过熟练地运用快捷键&a…...

认识jmeter接口测试工具!

jmeter简介 Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试&#xff0c;它最初被设计用于Web应用测试&#xff0c;但后来扩展到其他测试领域。 下载 下载地址&#xff1a;​​​​​​Apache JMeter - Download Apache JMeter 安装 由于Jmeter…...

强大的按钮类CButtonST

转自&#xff1a;哈哈 强大的CButtonST_cbuttonst demo-CSDN博客 这里给大家介绍强大的按钮类CButtonST&#xff0c;可以使您的程序锦上添花。 CButtonST类主要包括BtnST.h、BtnST.cpp、BCMenu.h和BCMenu.cpp四个文件。先将上述4个文件复制到自己的工程&#xff0c;然后在VC开…...

学习ing

记录 1.光圈的大小由一个称为“F值”的数字表示&#xff0c;这个数字越小&#xff0c;光圈就越大&#xff0c;光线也就越多。一般来说&#xff0c;使用较小的F值可以拍摄出更亮的照片&#xff0c;而使用较大的F值可以拍摄出更暗的照片。 2.光圈可以控制相机的曝光时间&#x…...

flash个人网站片头/自助建站系统模板

假定邻接矩阵为&#xff1a; 0 1 1 1 0 0 1 0 1 0 1 1 1 0 0 0 1 1 0 0 1 1 1 0 1 1 0 0 1 0 1 0 0 1 1 1 0 1 1 1 0 0 1 0 1 0 0 1 1 0 1 1 1 0 0 1 0 0 0 0 1 1 1 0 根据图着色算法已求得着色方案&#xff1a; 1 2 3 3 1 2 2 3 接下来可视化图着色结果 import ne…...

河北邢台沙河疫情最新消息/trinseo公司

1 判断数据库是否存在Sql代码 if exists (select * from sys.databases where name ’数据库名’) drop database [数据库名] if exists (select * from sys.databases where name ’数据库名’) drop database [数据库名]2 判断表是否存在Sql代码 if exists (select * …...

网站防盗链怎么做/seo搜索引擎优化技术

每日github继续更新&#xff1a;21&#xff0c;tensorflow / modelstensorflow已经训练好的一些模型。学习tensorflow从这里开始。22&#xff0c;electron / electron 如果你可以建一个网站&#xff0c;你就可以建一个桌面应用程序。 Electron 是一个使用 JavaScript, HTML 和 …...

wordpress回复下载插件/下载优化大师安装桌面

时间限制&#xff1a;1秒 空间限制&#xff1a;32768K 小易最近在数学课上学习到了集合的概念,集合有三个特征&#xff1a;1.确定性 2.互异性 3.无序性.小易的老师给了小易这样一个集合&#xff1a;S { p/q | w ≤ p ≤ x, y ≤ q ≤ z }需要根据给定的w&#xff0c;x&#xf…...

单县网站建设/seo网站优化流程

本系列译自jakob jenkov的Java并发多线程教程&#xff0c;个人觉得很有收获。由于个人水平有限&#xff0c;不对之处还望矫正&#xff01;Java内存模型指定Java虚拟机如何与计算机的内存(RAM)一起工作。Java虚拟机是整个计算机的一个模型&#xff0c;所以这个模型自然包含了一个…...

品牌网站建设gs/线上营销怎么推广

现代人许多人一直对保险表示怀疑&#xff0c;除了知道要上国家的社会保险&#xff0c;对商业保险一直是不太相信&#xff0c;认为保险大多是骗人的。 下面就几个大的问题&#xff0c;对大家详解一下&#xff01; 保险&#xff0c;生的时候拿不了&#xff0c;死才有得拿&#xf…...