命令式和声明式
- 命令式框架的一个最大的特点是关注过程, 如 jquery
- 声明式框架更加关注结果, 命令式实现上面的自然语言描述的功能,如 vue, react
// Vue.js帮我们封装了命令式的过程代码,然后暴露给我们的是这种声明式的 。
<div @click="()=>alert('ok')">hello world</div>
性能与可维护性的权衡
- 结论:声明式代码的性能 不优于 命令式代码的性能。
- 命令式代码的更新性能消耗=更新新内容的性能消耗;
- 声明式代码的更新性能消耗=更新新内容的性能消耗+找出差异的性能消耗;
- 只有找出差异的性能消耗足够的小无限接近于,性能才能向命令式靠近。
- Vue.js 使用声明式框架的主要理由就是可维护性高于命令式框架,框架设计者只能在保持可维护性的同时尽量让性能损耗最小化
关于虚拟 DOM 的性能
- JavaScript 层面的操作要比 DOM 操作快得多,速度不是一个数量级的
- 虚拟 DOM 树就是 JavaScript 对象,是真实的 DOM 描述, 操作虚拟 DOM 是 javaScript 层面的操作
性能对比
- 虚拟 DOM 创建新页面的过程是,第一步创建 JavaScript 对象,真实的 DOM 描述;第二步是 Diff 出差异,递归地遍历虚拟 DOM 树并创建真实的 DOM。
- innerHTML 创建页面性能 = HTML 字符串拼接的计算量 + innerHTML 的 DOM 计算量。
- 用虚拟 DOM 创建页面性能 = 创建 JavaScript 对象的计算量 + 创建真实 DOM 的计算量。
-
上面的公式可以看出来,无论是 JavaScript 层面的计算,还是 DOM 层面的计算,其实两者的差距几乎没有。
-
创建新页面时性能对比: 都需要创建新建所有的 DOM 元素。只从创建页面的性能对比来看的话,虚拟 DOM 根 innerHTML 没有什么优势。
-
页面更新时的性能对比:
-
innerHTML 是重新构建 HTML 字符串,再重新设置 DOM 元素的 innerHTML 属性,哪怕只是只改了一个字,也要重新设置 innerHTML 属性,要销毁所有旧的 DOM 元素,再全部重新创建新的 DOM 元素。
-
虚拟 DOM 的更新页面:创建新的 JavaScript 对象+Diff,多了一个 Diff 的性能消耗,这个消耗是 JavaScript 层面上运算,不会产生数量级的差异。Diff 作用是判断出页面仅更新的必要元素,而非全部元,所以性能优势极大;
-
更新页面时 ,innerHTML 的性能消耗是跟更新的页面大小相关的,更新的页面越大,性能的消耗也会越大。而虚拟 DOM 只会更新变化的那一部分元素。
运行时 和 编译时
1.纯运行时程序:灵活,简单,直接基于用户的调用的操作和入参,得到对应的结果
function render(要渲染的虚拟DOM数据,根节点) {
根基的.appendChild(字节的)
}
// 调用
render(obj, '#app')
纯运行时的缺点也很明显:用户的输入是在代码运行时,无法对用户的内容进行有效的分析和标记,不利于性能优化
- 编译时 + 运行时
- Vue.js3 是一个编译时+运行时的框架,它在保持灵活性的基础上,还能够通过编译手段分析用户提供的内容,从i而进一步提升更新性能。
// 模板
<tempalte>
<div>
<h1>{{ title }}</h1>
<ul>
<li v-for="item in list">{{ item }}</li>
<ul>
</div>
</tempalte>
// 渲染函数
function render(要渲染的虚拟DOM数据,根节点) {
根基的.appendChild(字节的)
}
// 编译函数
function compiler(模板) {
// 分析模板中用户内容
// 那些是静态的
// 那些是动态了
// 哪一个点是动的,打上标记
return 基于模板返回虚拟DOM
}
// 框架调用
// 编译
let vdom = compiler(template)
// 渲染
render(vdom, '#app')
//
- 优势1:声明式的template,提升用户体验, 开发更直观,易于维护
- 优势2:编译阶段可对用户代码 进行分析,可在编译成的新代码中打标记, 后续运行时基于标记继续代码性能优化
- 纯编译时:有以上的有点,但是用户提供的内容必须编译后才能运行,有损灵活性