【Vue.js设计与实现解读-1】
Vue设计与实现阅读-1
- 1、命令式和声明式
- 2、性能
- 3、虚拟DOM性能
- 4、运行时和编译时
- 5、总结
前言
最近工作清闲了些,想着很久没有看书,Vue.js设计与实现这本书看了好几次都没有读完,趁着这个机会边读边记录一下吧。如果有理解的不正确的地方,欢迎指出。
1、命令式和声明式
命令式: 关注过程
例如实现这样一个代码
-获取 id 为 app 的 div 标签-设置他的文本内容为hello world-为他绑定点击事件-点击时弹出提示:ok
const div = document.querySelector('#app');
div.innerText = 'hello world';
div.addEventListener('click', () => {alert('ok');
});
声明式: 关注结果
同样用声明式的写法实验上面的功能
<div @click="() => alert('ok')">hello world</div>
上面这个html模板采用的是Vue实现的方式,可以看出,我们提供的是一个结果,vue内部去帮我封装了这个过程,就像我们告诉vue:我需要一个div,他的文本内容是hello world,有一个绑定事件。可以猜测,Vue.js的内部实现是命令式的,暴露给用户的是声明式的。
2、性能
声明式代码的性能不优于命令式代码的性能。
例如,还是上面的例子,我们需要修改 div 中文本的内容为 hello Vue。
命令式的写法,直接调用相关命令
div.textContent = 'hello Vue' // 直接修改
声明式写法
// 修改前
<div @click="() => alert('ok')">hello world</div>
// 修改后
<div @click="() => alert('ok')">hello Vue</div>
从上面可以看出,命令式代码明确知道哪里发生了变更,只需要做必要的修改就行,但声明式还不一定能做到这一点。对于一个框架来说,为了实现最优的更新性能,他需要找到前后的差异且只更新变化的地方。
如果我们把直接修改的性能消耗定义为A,找出差异的消耗定义为B,则
命令式代码的更新性能消耗 = A声明式代码的更新新能消耗 = A + B
在性能层面命令式是更好的选择,为什么Vue.js要选择声明式设计方案。原因在于声明式的可维护性更强。在上面的例子中可以看到,如果采用声明式开发,我们需要维护实现目标的整个过程(DOM创建、更新、删除等),而命令式我们只需要关注结果就行。
3、虚拟DOM性能
声明式代码的更新新能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗。如果能够最小化找出差异的性能消耗,就可以让声明式代码的性能无限接近于命令式代码的性能。所谓的虚拟DOM,就是为了最小化找出差异这一步的性能消耗而出现的。
innerHTML创建页面的过程: 构造 HTML 字符串,将该字符串赋值给 DOM 元素的 innerHTML 属性。
const html = `<div><span></span></div>
`
div.innerHTML = html
innerHTML创建页面的性能:HTML 字符串拼接的计算量 + innerHTML 的 DOM 计算量
虚拟DOM创建页面过程:第一步,创建js对象(真实 dom),第二步递归遍历虚拟 dom 树并创建真实 dom
虚拟dom创建页面的性能:创建JS对象的计算量 + 创建真实 DOM 的计算量
从创建页面来看,两者差距不大,都是需要新建所有 DOM 元素。但是继续看下更新页面时的性能
innerHTML更新页面的过程:相当于重新构建HTML字符串,再设置 DOM 元素的 innerHTML 属性。相当于更改了一个文字,也需要重新设置 innerHTML 属性,等价于销毁所有旧的 DOM 元素,再全量创建新的 DOM 元素。
虚拟DOM更新页面过程:创建 js 对象(虚拟DOM树),比较新旧虚拟 DOM, 找到变化的元素更新他。
对比:在更新页面的时候,虚拟 DOM 在 js 层面比创建页面时多了个找 diff 的性能消耗,但是比较是 js 层面的运算,不会产生数量级的差异,再观察 DOM 层面的运算,虚拟 DOM 只需要更新边户的COM, 而 innerHTML 需要全量更新。
4、运行时和编译时
设计框架,我们有三种选择,纯运行时、运行时+编译时、纯编译时。
假设设计一个框架,提供一个 Render 函数,用户可以为该函数提供一个属性结构的数据对象,Render 函数会根据对象递归将数据渲染成 DOM 元素。
规定树形结构如下:
const obj = {tag: 'div',children: [{tag: 'span',children: 'hello world'}]
}
每个对象有两个属性,tag 标签名称, children 可以是数组,表示子节点,可以是文本表示文本子节点。
Render 函数实现
function Render(obj, root) {// 创建标签const el = document.createElement(obj.tag);// 如果是文本子节点if (typeof obj.children === 'string') {// 创建文本元素const text = document.createTextNode(obj.children);// 添加进标签元素el.appendChild(text);} else if (obj.children) {// 子节点,递归调用render 构造子元素obj.children.forEach((child) => Render(child, el))}// 将元素添加到根节点root.appendChild(el);
}
元素使用
Render(obj, document.boby);
可以发现,用户在使用Render函数渲染内容的时候,可以直接提供一个树形数据对象给 Render 对象,不涉及其他额外步骤。
有一天用户抱怨,手写树形数据对象太麻烦,不直观,想支持用类型HMTL标签的方式描述树形结构对象。发现刚写的Render函数并不能满足。刚实现的Render函数,是一个纯运行时的框架。
为满足用户需求,使用编译的手段 把HTML 标签变异成树形结构的数据对象。
<div><span>hello world</span>
</div>------ 经过编译 ------const obj = {tag: 'div',children: [{tag: 'span',children: 'hello world'}]}
假设 你编写了一个 Compiler 的程序,他的作用是将 HTML 字符串编译成树形结构的对象,用户需要分别调用 Compiler 和 Render 函数就能实现。
const html = `<div><span>hello world</span></div>
`
const obj = Compiler(html);
Render(obj, document.boby);
此时 框架变成了运行时 + 编译时。既支持运行时,用户可以直接提供数据对象无需编译;又支持编译时,用户可以提供 HTML字符串,我们将它编译成数据对象交给运行时处理。
那编译器可以把 HTML 变成成数据对象,应该也可以编译成命令式代码。
<div><span>hello world</span>
</div>------ 经过编译 ------const div = document.createElement('div');
const span = document.createElement('span');
span.innerText = 'hello world';
div.appendChild(span);
document.boby.appendChild(div);
这样我们只需要一个 Compiler 函数就行。这就成了一个纯编译时的框架。我们不支持任何运行时内容,用户的代码通过编译器编译后才能运行。
一个框架可以是上面说的这三种的任意一种
纯运行时,无编译过程,因此没办法分析用户提供的内容。如果加入编译,我们可以分析用户提供内容,看到哪些发生改变,哪些没有,
那我们可以在编译时提取这些信息,传递给 Render 函数,Render函数根据这些信息进一步优化。但是如果是纯编译时,她可以分析用户提供的内容,
由于不需要任何运行时,而是直接编译,那性能会更好,但是因为用户提供的内容必须通过编译才能使用,所以有损灵活性
Vue3保持运行时+编译时的架构,在保持灵活性的基础上能够尽可能地去优化。
5、总结
- 命令式和声明式,命令式关注过程,声明式关注结果
- 声明式的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗
- 虚拟dom存在的意义在于使找出差异的性能消耗最小化
- 运行时和编译时的差异,vue3是编译时+进行时的框架。
相关文章:
【Vue.js设计与实现解读-1】
Vue设计与实现阅读-1 1、命令式和声明式2、性能3、虚拟DOM性能4、运行时和编译时5、总结 前言 最近工作清闲了些,想着很久没有看书,Vue.js设计与实现这本书看了好几次都没有读完,趁着这个机会边读边记录一下吧。如果有理解的不正确的地方&…...
苗情生态自动监测系统-科普知识
随着科技的飞速发展,智能化技术在各个领域的应用越来越广泛。在农业领域,苗情生态自动监测系统的出现,为农业生产带来了革命性的变革。它不仅能够实时监测植物的生长状况,还能对环境因素进行全面监控,为农业生产提供科…...
test 系统学习-04-test converate 测试覆盖率 jacoco 原理介绍
测试覆盖率 测试覆盖率(test coverage)是衡量软件测试完整性的一个重要指标。掌握测试覆盖率数据,有利于客观认识软件质量,正确了解测试状态,有效改进测试工作。 当然,要发挥这些作用,前提是我们掌握了真实的测试覆盖…...
小型企业成为网络犯罪分子获取数据的目标
在过去十年的大部分时间里,网络犯罪的巨额资金来自针对大型组织的勒索软件攻击。这种威胁仍然存在。但犯罪分子可能会将注意力转向中小企业 (SMB)。这对消费者的影响将是巨大的。 将软件即服务 (SaaS) 技术用于核心业务功能继续将中小企业整合到全球供应链中。由于…...
PyTorch的Tensor(张量)
一、Tensor概念 什么是张量? 张量是一个多维数组,它是标量、向量、矩阵的高维拓展 Tensor与Variable Variable是torch.autograd中的数据类型,主要用于封装Tensor,进行自动求导。 data: 被包装的Tensorgrad: data的梯度&…...
spug发布问题汇总记录
问题导览 1. [vite]: Rollup failed to resolve import "element-plus" from "src/main.js". 项目框架简介 vue3viteelement-plus 解决方案 - 1. 配置淘宝镜像源:npm config set registry https://registry.npm.taobao.org/ - 2. npm inst…...
SpringBoot-搭建集成Mybatis的项目
本文介绍了如何在IntelliJ IDEA中使用SpringBoot和Mybatis构建Java Web应用程序。通过本文的学习,读者将了解如何使用IntelliJ IDEA快速搭建一个基于SpringBoot和Mybatis的Java Web应用程序,提高开发效率。IntelliJ IDEA是一款功能强大的Java集成开发环境…...
mysql隐式转换规则
MySQL 中的隐式类型转换发生在比较操作或者其他一些需要特定数据类型参数的上下文中,如果参与操作的表达式或列的数据类型不匹配,MySQL 就会自动进行数据类型转换以适配预期的数据类型。 以下是 MySQL 的一些常见隐式转换规则: 字符串和数字…...
怎么解决 Nginx反向代理加载速度慢?
Nginx反向代理加载速度慢可能由多种原因引起,以下是一些可能的解决方法: 1,网络延迟: 检查目标服务器的网络状况,确保其网络连接正常。如果目标服务器位于不同的地理位置,可能会有较大的网络延迟。考虑使用…...
Eureka工作原理超详细讲解介绍
Eureka 是 Netflix 开源的一款服务注册与发现框架,主要用于构建分布式系统中的服务治理和负载均衡。下面是关于 Eureka 工作原理的详细介绍:1.Eureka 架构: Eureka 采用了客户端-服务器架构,包括 Eureka Server 和 Eureka Client …...
SQL WHERE 语句(条件选择)
WHERE 子句用于过滤记录。 SQL WHERE 子句 WHERE 子句用于提取那些满足指定条件的记录。 SQL WHERE 语法 SELECT column1, column2, ... FROM table_name WHERE condition; 参数说明: column1, column2, ...:要选择的字段名称,可以为多…...
用UCLI(TCL)控制verdi dump 波形
UCLI(Unified Command-line Interface)为Synopsys验证工具了提供一组通用命令,通过UCLI可以执行任意TCL(Tool Command Language)命令。在我们的验证环境中,通常跟ucli打交道的地方是用来控制开始dump和结束…...
如何使用 Python+selenium 进行 web 自动化测试?
Selenium是一个自动化测试工具,它可以模拟用户在浏览器中的操作,比如点击、输入、选择等等。它支持多种浏览器,包括Chrome、Firefox、Safari等等,并且可以在多个平台上运行。 安装和配置Selenium 在使用Selenium之前,…...
约瑟夫问题
约瑟夫问题 题目描述 n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。…...
文件管理方法:利用文件大小进行筛选,高效移动文件至目标文件夹
在日常工作中,文件管理是一项至关重要的任务。为了更高效地管理文件,可以利用文件大小进行筛选,并将文件快速移动至目标文件夹。接下来一起来看看云炫文件管理器如何利用文件大小进行筛选,以及如何高效移动文件至目标文件夹的方法…...
python报错:TypeError: Descriptors cannot be created directly.
问题 报错提示: TypeError:不能直接创建描述符。 如果此调用来自 _pb2.py 文件,则您生成的代码已过期,必须使用 protoc > 3.19.0 重新生成。 如果您不能立即重新生成原型,其他一些可能的解决方法是: 1.…...
Linux 内核调试
文章目录 一、方法论 一、方法论 qemu 虚拟机 Linux内核学习 Linux 内核调试 一:概述 Linux 内核调试 二:ubuntu20.04安装qemu Linux 内核调试 三:《QEMU ARM guest support》翻译 Linux 内核调试 四:qemu-system-arm功能选项整…...
Prometheus-AlertManager 邮件告警
环境,软件准备 本次演示环境,我是在虚拟机上安装 Linux 系统来执行操作,以下是安装的软件及版本: System: CentOS Linux release 7.6Docker: 24.0.5Prometheus: v2.37.6Consul: 1.6.1 docker 安装prometheus,alertmanage,说明一下这里直接将…...
Volcano Controller控制器源码解析
Volcano Controller控制器源码解析 本文从源码的角度分析Volcano Controller相关功能的实现。 本篇Volcano版本为v1.8.0。 Volcano项目地址: https://github.com/volcano-sh/volcano controller命令main入口: cmd/controller-manager/main.go controller相关代码目录: pkg/co…...
开源协议简介和选择
软件国产化已经提到日程上了,先来研究一下开源协议。 引言 在追求“自由”的开源软件领域的同时不能忽视程序员的权益。为了激发程序员的创造力,现今世界上有超过60种的开源许可协议被开源促进组织(Open Source Initiative)所认可…...
大创项目推荐 深度学习卫星遥感图像检测与识别 -opencv python 目标检测
文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐…...
pod的环节
pod 是k8s当中最小的资源管理组件 Pod也是最小化运行容器化的应用的资源管理对象 Pod是一个抽象化的概念,可以理解为一个或多个容器化的集合 在一个pod当中运行一个容器,是最常用的方式 在一个pod当中同时运行多个容器,在一个pod当中可以…...
Unity | Shader基础知识番外(向量数学知识速成)
目录 一、向量定义 二、计算向量 三、向量的加法(连续行走) 四、向量的长度 五、单位向量 六、向量的点积 1 计算 2 作用 七、向量的叉乘 1 承上启下 2 叉乘结论 3 叉乘的计算(这里看不懂就百度叉乘计算) 八、欢迎收…...
一个小白的微不足道的见解关于未来
随着科技的不断发展,IT行业日益壮大,运维工程师在其中扮演着至关重要的角色。他们负责维护和管理企业的技术基础设施,确保系统的正常运行。然而,随着技术的进步和行业的变化,运维工程师的未来将面临着一系列挑战和机遇…...
图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)
一、图的遍历的定义: 从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次。(连通图与非连通图) 二、深度优先遍历(DFS); 1、访问指定的起始顶点; 2、若当前访问的顶点…...
抖店做不起来?新手常见起店失败问题总结,看下你中了几条?
我是王路飞。 能看到这篇文章的,肯定是处境符合标题内容了。 抖店的门槛很低,运营思路其实也不算难,但就是很多新手做不起来。 这中间,可能跟平台、项目没什么关系,而是跟你自己有关系,走错了方向&#…...
【每日面试题】精选java面试题之redis
Redis是什么?为什么要使用Redis? Redis是一个开源的高性能键值对存储数据库。它提供了多种数据结构,包括字符串、列表、集合、有序集合、哈希表等。Redis具有快速、可扩展、持久化、支持多种数据结构等特点,适用于缓存、消息队列…...
OSCP 靶场 - Vault
端口扫描 nmap nmap -O 192.168.162.172 smb枚举 smbmap(kali自带) //枚举GUEST用户可以使用的目录 smbmap -u GUEST -H 192.168.162.172 NTLMrelay—smbrelay 1.制作钓鱼文件 使用GitHub - xct/hashgrab: generate payloads that force authentication against an attacker…...
uniapp子组件向父组件传值
目录 子组件向父组件传值子组件1子组件2 父组件最后 子组件向父组件传值 子组件1 <template><view class"content"><view v-for"(item,index) in list" :key"index">{{item}}</view></view> </template>&…...
过滤特殊 微信昵称
$nickName preg_replace(/[\xf0-\xf7].{3}/, , $userData[nickName]);...
wordpress 页脚改颜色/小程序开发收费价目表
cookie的实现很简单,在服务器返回的响应中,header里增加Set-Cookie,浏览器接受到Set-Cookie中的value,下次访问这个网站的请求中就会带上这个cookie。编写一个增加cookie的函数: def add_cookie(cookie):header HTTP…...
杭州做网站五/seo网站优化培训怎么样
冒泡排序 通过相邻元素的比较和交换,使得每一趟循环都能找到未有序数组的最大值或最小值。 // 最好:O(n),只需要冒泡一次数组就有序了。 // 最坏:O(n) // 平均:O(n) function bubbleSort(arr){for(let i 0,len arr.l…...
厦门外贸网站建设多少钱/百度如何做推广
arpspoof是一个好用的ARP欺骗工具,Kali linux中自带了该工具,在ubuntu中,安装它只需运行命令:sudo apt-get install dsniff安装完成后,输入命令:man arpspoof 可以查看使用手册,2.4版本的手册内…...
北京网站优化怎么样/免费seo搜索优化
数据结构(一) 1. 概述 数据结构定义: 我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(如元素的CURD、排序等)而执行的相应操作,这个相应的操作也叫算法。 数据结构 元素 元素的关系 算法…...
电子商务网站规划流程/网络推广网站推广方法
转自:http://www.cnblogs.com/jcchen1987/p/4581651.html 关于boost算法 boost算法是基于PAC学习理论(probably approximately correct)而建立的一套集成学习算法(ensemble learning)。其根本思想在于通过多个简单的弱分类器,构建…...
做cpa用什么网站/网站百度权重
在使用Ueditor时,如要简化工具栏上的按钮,可以修改配置项的方法: 1. 方法一:修改 ueditor.config.js 里面的 toolbars 2. 方法二:实例化编辑器的时候传入 toolbars 参数 我一般用第二种方法, <script sr…...