自学网站建设 难吗,巩义网站建设方案书,asp.net做网站如何展示界面,工程信息价在哪查询Vue设计与实现阅读-1 1、命令式和声明式2、性能3、虚拟DOM性能4、运行时和编译时5、总结 前言 最近工作清闲了些#xff0c;想着很久没有看书#xff0c;Vue.js设计与实现这本书看了好几次都没有读完#xff0c;趁着这个机会边读边记录一下吧。如果有理解的不正确的地方想着很久没有看书Vue.js设计与实现这本书看了好几次都没有读完趁着这个机会边读边记录一下吧。如果有理解的不正确的地方欢迎指出。 1、命令式和声明式
命令式 关注过程
例如实现这样一个代码 -获取 id 为 app 的 div 标签-设置他的文本内容为hello world-为他绑定点击事件-点击时弹出提示okconst 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 divspan/span/divdiv.innerHTML htmlinnerHTML创建页面的性能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 标签变异成树形结构的数据对象。
divspanhello world/span
/div------ 经过编译 ------const obj {tag: div,children: [{tag: span,children: hello world}]}假设 你编写了一个 Compiler 的程序他的作用是将 HTML 字符串编译成树形结构的对象用户需要分别调用 Compiler 和 Render 函数就能实现。
const html divspanhello world/span/divconst obj Compiler(html);
Render(obj, document.boby);此时 框架变成了运行时 编译时。既支持运行时用户可以直接提供数据对象无需编译又支持编译时用户可以提供 HTML字符串我们将它编译成数据对象交给运行时处理。 那编译器可以把 HTML 变成成数据对象应该也可以编译成命令式代码。
divspanhello 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是编译时进行时的框架。