Vue.js设计与实现,读书笔记第一章

news2024/11/16 17:33:40

第一章:权衡的艺术

1.1命令式和声明式

jq是命令式,关注过程,jq针对简化dom 而产生的

vue是 声明式,关注实现,不严格地说就像是在命令式(关注过程)基础上再对标签进行了一次封装(关注实现)

jQuery命令式关注过程简化dom 而产生的
Vue声明式关注实现针对用户产生声明部分

而事实也是,vue内部是命令式,但呈现给用户(程序员)的是声明式的部分

1.2性能与可维护性的权衡

性能对比原则或理论:基于以上比较,理论上声明式在性能上是不能超过命令式的

//不过命令式要代码一一对应实现,初次学习,感觉vue会在复用性上优化性能

而且在声明式的部分,是无法做到内部命令式的部分操作的,vue的把命令的部分交给了自己的源码,用户只需操作得到自己想要的即可,确实提升开发效率

例如:`

而声明式不需要我们关心DOM元素的创建更新删除

//本质都是对dom的操作,声明式原本性能并不比定义式强,只是复用起来,省去了许多声明,从而在整体上优化了性能;官网文档有和react的比较,再写

而之所以性能不如定义式,在于,面向用户的声明式要进行B(代替找出差异消耗的性能)

对于B:一个框架在对元素进行修改(场景就是维护项目),需要

比对需要修改的地方,这里所消耗的性能`用B代替

面向用户的命令式部分就是多了这部分B,

//挺抽象哈,这个例子很形象的帮我理解了两种差别

1.3虚拟DOM的性能到底如何

前置条件:由于很难写出绝对极致的命令式语句;即使写出了,也消耗了相当高的成本,投入产出并不高;因此产生了虚拟DOM,执行B,寻求产出比的下限

以上内容其实是针对JavaScript中的DOM来讲的,我们首先要清楚框架的核心其实就是简化DOM操作目前来讲,当然他配套的生态也十分的重要

在学习《JavaScript DOM编程艺术》一书中提到相同的问题;就是innerHTML的特殊性,下面展开来讲:

innerHTML创建网页需要构造一段HTML字符串

const html ='<div><span>...</span></div>'

接着讲此字符串赋值给DOM元素的innerHTML属性

div.innerHTML =html

远没有上面两句话那么简单:为了渲染页面,首先字符串要解析成DOM树,涉及到DOM层的运算必然不如JavaScript层面

用1万次测试

 

因为是万次级别的测试,但我们仍看出了性能差别上命令部分比原生js几乎差了1倍

自此inner HTML创建网页的性能公式:A+B,
A:HTML字符串拼接的计算量+inner HTML的DOM计算量

那么虚拟DOM是如何渲染我们的页面的?

//准确来说是创建

两步:

1.创建JavaScript对象(这里的对象可以理解为真实的DOM)

2.递归遍历虚拟DOM树并创建真实DOM(虚拟dom的虚拟原来是指遍历虚拟dom树)

虚拟DOM的性能公式:A十B;A:创建.TavaScripti的计算量B:创建真实DOM的计算量

 

 

 

可以看出innerHTML更新页面的过程就是重新构建HTML字符串,再重新设置DOM;

这需要我们即使只修改了一个文字,也要全部执行者3部操作;而且是销毁

全部旧DOM元素,全量创建新的DOM元素

//这点上我觉得和jq中学习深浅拷贝有关系;简单来说就是命令式会覆盖(比如jq对象的浅拷贝覆盖,深拷贝保留)

看看我们虚拟dom是怎么更新页面数据的:

B的对比不同在这方面起到了不同

也就是:虚拟dom只更新需要更新的局部内容,这就是虚拟dom的优势,你可能会说上面的diff性能消耗,这一算法在后面会分析,这里提一句diff算法在JavaScript层面运算,不会产生数量级的差异(差异有但不明显,忽略);反正能原生层面解决的东西性能肯定不会差

于是各自性能与什么条件有关就显现在下面了:

 

正在上传…重新上传取消

innerHTML在页面越大时,更新性能消耗越大;虚拟dom和更新量有关

//这里vue的虚拟dom是不是用的diff算法来监测不同的,留个疑问

粗略比较下原生,虚拟dom和innerhtml这三者在更新页面时的性能:

 

正在上传…重新上传取消

这里原生JavaScript指的是它的dom操作

所谓心智指的是:传统的增删改查,也就是:手动创建,删除,修改大量dom原素

innerHTML在字符串拼接方面表现的有些接近声明了

//命令式和声明式只是个帮助我们理解的名词,不要认为vue有,其他的框架就不能有类似的地方

1.4运行时和编译时

那么综合上面各项指标的取舍,有没有鱼和熊掌兼得的东西

//折中

设计框架时有三种选择:纯运行时的,运行时+编译时的或纯编译时的

聊聊纯运行时:

假设设计了个框架,提供了一个Render函数,用户只需要提供一个树形结构的数据对象;之后这个函数会递归地将数据渲染成DOM元素

规定树形结构的数据对象如下:

 const obj = {
      tagL: '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,使用el作为root参数
        obj.children.array.forEach((child)=>Render(child,el))
      }
      //元素添加到 root
      root.appendChild(el)
    }

用户实现提交,无需额外学习知识,不需要额外步骤,为Render提供一个树形结构的数据对象即可;

// 用户实现
    const obj = {
      tag: 'div',
      children: [
        {
          tag: 'span',
          children: 'hello world',
        },
      ],
    };
    //渲染到body下
    // Render(onj, document.body)

直到有一天用户抱怨:不愿意手写数据结构对象,而且不直观,能不能用类似HTML标签的方式描绘数据结构对象呢,你看了看Render函数,摇了摇头,暂不支持,以上就是一个纯运行时的框架

为了满足用户需求,你开始思考能不能引入编译的手段,把HTML编译成树形结构的数据对象,这样我们就可以继续使用Render函数了

 

为此我们要写一个名为Complier的程序,作用就是实现上面把HTML字符串(标签里的东西)编译成树形结构的数据对象

用户怎么用呢,最简单的就是让用户分别调用Compiler函数和Render函数:

//设计运行时+编译时框架
    const html = `<div>
        <span> hello world</span>
      </div>`
      // 看起来``和()在这里作用似乎是一样的
      //调用Complier 编译器得到属性结构的数据对象
      const obj= Compiler(html)
      //再调用Render进行渲染
      Render(obj,document.body)

以上 构成了运行时加编译时的框架;准确讲是运行时编译

具体来讲它支持运行时,用户可以直接提供数据对象而无需编译;又支持编译时,用户可以提供(?)字符串,我们将其编译为数据对象后交付运行处理

也就是代码运行时才开始编译,而这会产生一定性能的开销,因此我们也可以在构建阶段就执行compiler将用户提供的内容编译好,等运行就不用编译了,这对性能是友好的

这引起我们的思考,既然编译器可以把HTML字符串编译成数据对象,那为何不直接编译成命令式代码呢?

于是

 

这样我们只需要一个compliler函数就可以了,甚至连Render都不需要了

然后这就变成了纯编译的框架;然而我们不支持任何运行内容时(这是指什么?),用户代码只能通过编译器编译后才能执行

上面用例子解释了3种方法

那他们都有哪些优缺点呢,在什么场景下能发挥各自的优势呢?

总结如下:

纯运行自然效率强,但无法分析用户提供的内容;如果加入编译,则解决这个问题,传递给我们的Render函数,执行优化;如果是纯编译,则灵活性不高,心智负载大因此vue3出现了

1.5总结

首先

我们讨论了命令式和声明式的差异,其中命令式关注过程(就是日常按步骤把功能实现为代码),声明式关注结果(更加)

命令式在理论上的性能是极致的,心智损耗也更大;声明式减少了心智负担,相应的在性能上有“一定”的牺牲

框架设计者要把这种牺牲尽可能想办法损耗最小化

//仁慈的独裁者,这种理想只出现在开源社区

接着

我们讨论了虚拟DOM的性能(框架设计者为了解决上面问题),给出了一个公式“声明式的更新性能消耗=找出差异的性能消耗+直接修改的性能消耗”

//和上面A+B的顺序颠倒了下,无先后

从而

我们明白虚拟DOM的意义在于使找出差异(B)性能消耗最小化

发现

我们发现不能以偏概全地描述原生,虚拟DOM,innerHTML的性能,而应该把比较放在具体的场景中:这与页面大小,变更部分的大小有关还与是创建页面还是更新页面有关,而选择哪种变更,结合了心智负担和可维护性等因素综合考虑

最终

我们发现虚拟DOM综合来看是个不错的选择

最后我们提了下vue是个运行时+编译时的框架,并对比,发现它在保持灵活性的基础上还能用过编译手段分析用户提供的内容,从而进一步提升了更新性能

//这使得vue不是简单的取舍,而是真正优化了DOM节点操作

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

干货 | Jmeter 如何保证抢购、秒杀活动正常运行?

1. 前言 平常为了保证运营促销、抽奖活动能正常运行&#xff0c;我们一般都需要使用 Jmeter、LoadRunner 对接口进行压力测试 使用它可以模拟一定量的用户同时去参与促销抽奖活动&#xff0c;最后生成测试报告&#xff0c;以此判系统接口的稳定性 本篇文章以抢购商品为例&am…

清华毕业大佬用了一个项目就把SpringMVC+Spring+MyBatis给讲完了

前言 时间飞逝&#xff0c;转眼间毕业七年多&#xff0c;从事 Java 开发也六年了。我在想&#xff0c;也是时候将自己的 Java 整理成一套体系。 这一次的知识体系面试题涉及到 Java 知识部分、性能优化、微服务、并发编程、开源框架、分布式等多个方面的知识点。 写这一套 Ja…

R语言学习笔记——入门篇:第五章-高级数据管理

R语言 R语言学习笔记——入门篇&#xff1a;第五章-高级数据管理 文章目录R语言一、数值与字符处理函数1.1、数学函数1.2、统计函数1.3、概率函数1.4、字符处理函数1.5、其他实用函数1.6、将函数应用于矩阵与数据框二、控制流2.1、循环&#xff08;for&#xff0c;while&#…

从零开始带你实现一套自己的CI/CD(三)Jenkins+Harbor

目录一、简介二、安装Harbor2.1 Amd64架构安装Harbor2.2 Arm64架构安装Harbor找不到make命令找不到git命令执行make download和make compile_redis失败执行make compile_redis命令执行make prepare_arm_data命令执行make pre_update命令执行make compile COMPILETAGcompile_gol…

【OpenCV-Python】教程:4-4 SIFT 介绍

OpenCV Python SIFT (尺度不变特征变换) 【目标】 SIFT算法SIFT特征点和描述子 【理论】 前面的章节中&#xff0c;我们提到了角点检测&#xff0c;例如Harris角点&#xff0c;他们是旋转不变的&#xff0c;因为&#xff0c;图像无论如何旋转&#xff0c;其角点特性不会发生…

世界杯8强盘点

2022年卡塔尔世界杯&#xff08;英语&#xff1a;FIFA World Cup Qatar 2022&#xff09;是第二十二届世界杯足球赛&#xff0c;是历史上首次在卡塔尔和中东国家境内举行、也是第二次在亚洲举行的世界杯足球赛。除此之外&#xff0c;卡塔尔世界杯还是首次在北半球冬季举行、首次…

docker(八)compose

compose 一 简介&#xff1a; 通过前面几篇文章&#xff0c;我们了解了docker的基本知识&#xff0c;docker帮我们解决了服务打包安装的问题&#xff0c;但是随着服务的不断增多带来了如下问题&#xff1a; 多次使用Dockerfile Build Image或者DockerHub拉取Image;需要创建多…

Spark 动态资源分配参数与源码原理分析

1.1.1、Dynamic Allocation 1.1.1.1 参数说明 1.2 版本 参数名及默认值含义spark.dynamicAllocation.enabled false是否开启动态资源分配&#xff0c;主要是基于集群负载分配executorspark.dynamicAllocation.executorIdleTimeout60sexecutor空闲时间达到规定值&#xff0c…

程序人生:化解互联网 “寒冬” 危机,我教你摆脱困境

三年反复的yi情&#xff0c;近20年史无前例的互联网裁员潮汹涌而至。 寒冬来袭&#xff0c;每一个职场打工人&#xff0c;都感到了寒意。 互联网企业大裁员的底层逻辑&#xff0c;一方面是受宏观环境影响&#xff08;yq、互联网红利结束、政策变化等&#xff09;&#xff0c;…

ChatGPT震撼上市,AI也开始跟你卷了,来一起看看怎么用ChatGPT!!!

强大AI产品&#xff0c;ChatGPT震撼上市&#xff0c;程序员真的要失业了吗&#xff1f; 最近聊天机器人异常火爆&#xff0c;火爆到什么程度&#xff0c;卖个关子&#xff0c;下文解释。 OpenAI推出了ChatGPT&#xff0c;它能够回答各种各样的问题&#xff0c;包括生成代码&a…

Node.js学习下(70th)

一、Buffer 缓冲区 背景 1、浏览器没有储存图片文件等媒体文件的需求&#xff0c;JS 存的都是一些基本数据类型。 2、服务器需要存储图片/视频/音频等媒体文件&#xff0c;因此有了 Buffer 缓冲器。 1. Buffer 是什么 Buffer 是一个和数组类似的对象&#xff0c;不同是 Buf…

python代码学习1

\n 换行符号 \r 回车 \b 后退一个格 \t 制表符&#xff08;4个字符为一组&#xff0c;当不字符被占有时&#xff0c;重新生成一个制表符。如果被占据&#xff0c;不满4个字符时&#xff0c;生成剩余部分空格。&#xff09; #原字符 不希望字符串中转义字符起作用&#xff0…

FME Server 无代码环境中自动化您数据和应用集成工作流

专为现代企业打造 简化数据和应用程序集成&#xff0c;让您的数据为您所用。在FME Desktop中创作工作流&#xff0c;并使用 FME Server 将其自动化&#xff0c;以按计划或响应事件运行数据集成。 构建无代码 Web 应用程序&#xff0c;提供自助式数据提交和验证&#xff0c;并向…

Java学习之动态绑定机制

目录 举例说明 父类 子类 main类 运行结果 ​编辑 动态绑定 举例说明 父类 子类 main类 分析 运行结果 Java重要特性&#xff1a;动态绑定机制&#xff08;非常重要&#xff09; 举例说明 父类 class A {//父类public int i 10;public int sum() {return getI(…

2022年11月国产数据库大事记-墨天轮

本文为墨天轮社区整理的2022年11月国产数据库大事件和重要产品发布消息。 文章目录11月国产数据库大事记&#xff08;时间线&#xff09;产品/版本发布兼容认证排行榜新增数据库11月国产数据库大事记&#xff08;时间线&#xff09; 11月1日&#xff0c;国际知名研究机构 IDC …

什么是内存对齐

内存对齐 什么是内存对齐为什么要内存对齐内存对齐的规则结构体中内存对齐 sizeof无嵌套有嵌套 iOS中对象内存对齐 iOS中获取内存大小方式 class_getInstanceSize()malloc_size() iOS中内存对齐 实际占用内存对齐方式系统分配内存对齐方式问题 内存优化 总结 内存对齐 什么…

基于C++的AGV机器人无线控制

1 AGV系统概述 1.1AGV原理 AGV行走控制系统由控制面板、导向传感器、方向电位器、状态指示灯、避障传感器、光电控制信号传感器、驱动单元、导引磁条、电源组成。 AGV的导引&#xff08;Guidance&#xff09;是指根据AGV导向传感器&#xff08;Navigation&#xff09;所得到…

基于FFmpeg进行rtsp推流及拉流(详细教程)

目录 1.1 Windows系统 1.2 Ubuntu 和 Debian 系统 1.3 CentOS 和 Fedora 系统 1.4 macOS系统 2. 安装rtsp-simple-server 3. FFmpeg推流 3.1 UDP推流 3.2 TCP推流 3.3 循环推流 4 拉流 4.1 ffplay/VLC拉流显示 4.2 FFmpeg拉流保存成视频 1. 安装FFmpeg FFmpeg 是一…

tftp服务/nfs服务/二进制工具集/uboot基础

一、什么是系统移植 1&#xff09;系统移植就是给开发板搭建一个linux操作系统 2&#xff09;从官方获取源码&#xff0c;进行配置和编译&#xff0c;生成板子需要的镜像文件 二、为什么系统移植 1&#xff09;为后面学习驱动开发课程打基础 2&#xff09;驱动开发工程师必…

入行4年,跳槽2次,在软件测试这一行我已经悟了!

近年来&#xff0c;软件测试行业如火如荼。互联网及许多传统公司对于软件测试人员的需求缺口逐年增大。然而&#xff0c;20年的疫情导致大规模裁员&#xff0c;让人觉得行业寒冬已经到来。软件测试人员的职业规划值得我们深思。 大家对软件测试行业比较看好&#xff0c;只是因…